Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
galene
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
galene
Commits
66e5d295
Commit
66e5d295
authored
Feb 01, 2022
by
Juliusz Chroboczek
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rework file transfer code.
More explicit data structures, better error handling.
parent
0ef5d107
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
246 additions
and
236 deletions
+246
-236
static/galene.js
static/galene.js
+246
-236
No files found.
static/galene.js
View file @
66e5d295
...
@@ -2153,74 +2153,93 @@ async function gotJoined(kind, group, perms, status, data, message) {
...
@@ -2153,74 +2153,93 @@ async function gotJoined(kind, group, perms, status, data, message) {
}
}
}
}
/**
/** @type {Object<string,TransferredFile>} */
* @typedef {Object} transferredFile
* @property {string} id
* @property {string} username
* @property {string} name
* @property {File} [file]
* @property {RTCPeerConnection} [pc]
* @property {number} size
* @property {string} type
* @property {Array<RTCIceCandidateInit>} [candidates]
* @property {Array<Blob|ArrayBuffer>} [data]
* @property {number} [datalen]
* @property {boolean} [done]
*/
/** @type {Object<string,transferredFile>} */
let
transferredFiles
=
{};
let
transferredFiles
=
{};
/**
/**
*
@param {boolean} up
*
A file in the process of being transferred.
*
@param {string} id
*
* @
param {string} fileid
* @
constructor
*/
*/
function
transferredFileId
(
up
,
id
,
fileid
)
{
function
TransferredFile
(
id
,
userid
,
up
,
username
,
name
,
type
,
size
)
{
return
id
+
(
up
?
'
+
'
:
'
-
'
)
+
fileid
;
/** @type {string} */
this
.
id
=
id
;
/** @type {string} */
this
.
userid
=
userid
;
/** @type {boolean} */
this
.
up
=
up
;
/** @type {string} */
this
.
username
=
username
;
/** @type {string} */
this
.
name
=
name
;
/** @type {string} */
this
.
type
=
type
;
/** @type {number} */
this
.
size
=
size
;
/** @type {File} */
this
.
file
=
null
;
/** @type {RTCPeerConnection} */
this
.
pc
=
null
;
/** @type {RTCDataChannel} */
this
.
dc
=
null
;
/** @type {Array<RTCIceCandidateInit>} */
this
.
candidates
=
[];
/** @type {Array<Blob|ArrayBuffer>} */
this
.
data
=
[];
/** @type {number} */
this
.
datalen
=
0
;
}
}
TransferredFile
.
prototype
.
fullid
=
function
()
{
return
this
.
userid
+
(
this
.
up
?
'
+
'
:
'
-
'
)
+
this
.
id
;
};
/**
/**
* @param {boolean} up
* @param {boolean} up
* @param {string} id
* @param {string}
user
id
* @param {string} fileid
* @param {string} fileid
* @returns {
t
ransferredFile}
* @returns {
T
ransferredFile}
*/
*/
function
getTransferredFile
(
up
,
id
,
fileid
)
{
TransferredFile
.
get
=
function
(
up
,
userid
,
fileid
)
{
let
f
=
transferredFiles
[
transferredFileId
(
up
,
id
,
fileid
)];
return
transferredFiles
[
userid
+
(
up
?
'
+
'
:
'
-
'
)
+
fileid
];
if
(
!
f
)
{
};
throw
new
Error
(
"
Couldn't find file being transferred
"
);
}
TransferredFile
.
prototype
.
close
=
function
()
{
return
f
;
if
(
this
.
pc
)
this
.
pc
.
close
();
this
.
dc
=
null
;
this
.
pc
=
null
;
this
.
data
=
[];
this
.
datalen
=
0
;
delete
(
transferredFiles
[
this
.
fullid
()]);
}
}
/**
TransferredFile
.
prototype
.
pushData
=
function
(
data
)
{
* @param {boolean} up
if
(
data
instanceof
Blob
)
{
* @param {string} id
this
.
datalen
+=
data
.
size
;
* @param {string} fileid
}
else
if
(
data
instanceof
ArrayBuffer
)
{
*/
this
.
datalen
+=
data
.
byteLength
;
function
deleteTransferredFile
(
up
,
id
,
fileid
)
{
}
else
{
let
fullid
=
transferredFileId
(
up
,
id
,
fileid
);
throw
new
Error
(
'
unexpected type for received data
'
);
let
f
=
transferredFiles
[
fullid
];
if
(
!
f
)
return
;
if
(
f
.
pc
)
{
f
.
pc
.
close
();
delete
(
f
.
pc
);
}
}
delete
(
transferredFiles
[
fullid
]);
this
.
data
.
push
(
data
);
}
TransferredFile
.
prototype
.
getData
=
function
()
{
let
blob
=
new
Blob
(
this
.
data
,
{
type
:
this
.
type
});
if
(
blob
.
size
!=
this
.
datalen
)
throw
new
Error
(
'
Inconsistent data size
'
);
this
.
data
=
[];
this
.
datalen
=
0
;
return
blob
;
}
}
/**
/**
* @param {boolean} up
* @param {TransferredFile} f
* @param {string} id
* @param {string} fileid
* @param {transferredFile} f
*/
*/
function
fileTransferBox
(
up
,
id
,
fileid
,
f
)
{
function
fileTransferBox
(
f
)
{
let
fullid
=
transferredFileId
(
up
,
id
,
fileid
);
let
p
=
document
.
createElement
(
'
p
'
);
let
p
=
document
.
createElement
(
'
p
'
);
if
(
up
)
if
(
f
.
up
)
p
.
textContent
=
p
.
textContent
=
`We have offered to send a file called "
${
f
.
name
}
" `
+
`We have offered to send a file called "
${
f
.
name
}
" `
+
`to user
${
f
.
username
}
.`
;
`to user
${
f
.
username
}
.`
;
...
@@ -2229,35 +2248,35 @@ function fileTransferBox(up, id, fileid, f) {
...
@@ -2229,35 +2248,35 @@ function fileTransferBox(up, id, fileid, f) {
`User
${
f
.
username
}
offered to send us a file `
+
`User
${
f
.
username
}
offered to send us a file `
+
`called "
${
f
.
name
}
" of size
${
f
.
size
}
.`
`called "
${
f
.
name
}
" of size
${
f
.
size
}
.`
let
bno
=
null
,
byes
=
null
;
let
bno
=
null
,
byes
=
null
;
if
(
up
)
{
if
(
f
.
up
)
{
bno
=
document
.
createElement
(
'
button
'
);
bno
=
document
.
createElement
(
'
button
'
);
bno
.
textContent
=
'
Cancel
'
;
bno
.
textContent
=
'
Cancel
'
;
bno
.
onclick
=
function
(
e
)
{
bno
.
onclick
=
function
(
e
)
{
cancelFile
(
id
,
fileid
);
cancelFile
(
f
);
};
};
bno
.
id
=
"
bno-
"
+
f
ullid
;
bno
.
id
=
"
bno-
"
+
f
.
fullid
()
;
}
else
{
}
else
{
byes
=
document
.
createElement
(
'
button
'
);
byes
=
document
.
createElement
(
'
button
'
);
byes
.
textContent
=
'
Accept
'
;
byes
.
textContent
=
'
Accept
'
;
byes
.
onclick
=
function
(
e
)
{
byes
.
onclick
=
function
(
e
)
{
getFile
(
id
,
fileid
);
getFile
(
f
);
};
};
byes
.
id
=
"
byes-
"
+
f
ullid
;
byes
.
id
=
"
byes-
"
+
f
.
fullid
()
;
bno
=
document
.
createElement
(
'
button
'
);
bno
=
document
.
createElement
(
'
button
'
);
bno
.
textContent
=
'
Decline
'
;
bno
.
textContent
=
'
Decline
'
;
bno
.
onclick
=
function
(
e
)
{
bno
.
onclick
=
function
(
e
)
{
rejectFile
(
id
,
fileid
);
rejectFile
(
f
);
};
};
bno
.
id
=
"
bno-
"
+
f
ullid
;
bno
.
id
=
"
bno-
"
+
f
.
fullid
()
;
}
}
let
status
=
document
.
createElement
(
'
div
'
);
let
status
=
document
.
createElement
(
'
div
'
);
status
.
id
=
'
status-
'
+
f
ullid
;
status
.
id
=
'
status-
'
+
f
.
fullid
()
;
if
(
!
up
)
{
if
(
!
f
.
up
)
{
status
.
textContent
=
status
.
textContent
=
'
(Choosing "Accept" will disclose your IP address.)
'
;
'
(Choosing "Accept" will disclose your IP address.)
'
;
}
}
let
div
=
document
.
createElement
(
'
div
'
);
let
div
=
document
.
createElement
(
'
div
'
);
div
.
id
=
'
file-
'
+
f
ullid
;
div
.
id
=
'
file-
'
+
f
.
fullid
()
;
div
.
appendChild
(
p
);
div
.
appendChild
(
p
);
if
(
byes
)
if
(
byes
)
div
.
appendChild
(
byes
);
div
.
appendChild
(
byes
);
...
@@ -2266,36 +2285,34 @@ function fileTransferBox(up, id, fileid, f) {
...
@@ -2266,36 +2285,34 @@ function fileTransferBox(up, id, fileid, f) {
div
.
appendChild
(
status
);
div
.
appendChild
(
status
);
div
.
classList
.
add
(
'
message
'
);
div
.
classList
.
add
(
'
message
'
);
div
.
classList
.
add
(
'
message-private
'
);
div
.
classList
.
add
(
'
message-private
'
);
div
.
classList
.
add
(
'
message-row
'
);
let
box
=
document
.
getElementById
(
'
box
'
);
let
box
=
document
.
getElementById
(
'
box
'
);
box
.
appendChild
(
div
);
box
.
appendChild
(
div
);
return
div
;
return
div
;
}
}
/**
/**
* @param {boolean} up
* @param {TransferredFile} f
* @param {string} id
* @param {string} fileid
* @param {string} status
* @param {string} status
* @param {boolean} [delyes]
* @param {boolean} [delyes]
* @param {boolean} [delno]
* @param {boolean} [delno]
*/
*/
function
setFileStatus
(
up
,
id
,
fileid
,
status
,
delyes
,
delno
)
{
function
setFileStatus
(
f
,
status
,
delyes
,
delno
)
{
let
fullid
=
transferredFileId
(
up
,
id
,
fileid
)
let
statusdiv
=
document
.
getElementById
(
'
status-
'
+
f
.
fullid
());
let
statusdiv
=
document
.
getElementById
(
'
status-
'
+
fullid
);
if
(
!
statusdiv
)
if
(
!
statusdiv
)
throw
new
Error
(
"
Couldn't find statusdiv
"
);
throw
new
Error
(
"
Couldn't find statusdiv
"
);
statusdiv
.
textContent
=
status
;
statusdiv
.
textContent
=
status
;
if
(
delyes
||
delno
)
{
if
(
delyes
||
delno
)
{
let
div
=
document
.
getElementById
(
'
file-
'
+
f
ullid
);
let
div
=
document
.
getElementById
(
'
file-
'
+
f
.
fullid
()
);
if
(
!
div
)
if
(
!
div
)
throw
new
Error
(
"
Couldn't find file div
"
);
throw
new
Error
(
"
Couldn't find file div
"
);
if
(
delyes
)
{
if
(
delyes
)
{
let
byes
=
document
.
getElementById
(
'
byes-
'
+
f
ullid
)
let
byes
=
document
.
getElementById
(
'
byes-
'
+
f
.
fullid
()
)
if
(
byes
)
if
(
byes
)
div
.
removeChild
(
byes
);
div
.
removeChild
(
byes
);
}
}
if
(
delno
)
{
if
(
delno
)
{
let
bno
=
document
.
getElementById
(
'
bno-
'
+
f
ullid
)
let
bno
=
document
.
getElementById
(
'
bno-
'
+
f
.
fullid
()
)
if
(
bno
)
if
(
bno
)
div
.
removeChild
(
bno
);
div
.
removeChild
(
bno
);
}
}
...
@@ -2303,15 +2320,13 @@ function setFileStatus(up, id, fileid, status, delyes, delno) {
...
@@ -2303,15 +2320,13 @@ function setFileStatus(up, id, fileid, status, delyes, delno) {
}
}
/**
/**
* @param {boolean} up
* @param {TransferredFile} f
* @param {string} id
* @param {string} fileid
* @param {any} message
* @param {any} message
*/
*/
function
failFile
(
up
,
id
,
fileid
,
message
)
{
function
failFile
(
f
,
message
)
{
console
.
error
(
'
File transfer failed:
'
,
message
);
console
.
error
(
'
File transfer failed:
'
,
message
);
setFileStatus
(
up
,
id
,
fileid
,
message
?
`Failed:
${
message
}
`
:
'
Failed.
'
);
setFileStatus
(
f
,
message
?
`Failed:
${
message
}
`
:
'
Failed.
'
);
deleteTransferredFile
(
true
,
id
,
fileid
);
f
.
close
(
);
}
}
/**
/**
...
@@ -2321,50 +2336,43 @@ function failFile(up, id, fileid, message) {
...
@@ -2321,50 +2336,43 @@ function failFile(up, id, fileid, message) {
*/
*/
function
offerFile
(
username
,
id
,
file
)
{
function
offerFile
(
username
,
id
,
file
)
{
let
fileid
=
newRandomId
();
let
fileid
=
newRandomId
();
let
fullid
=
transferredFileId
(
true
,
id
,
fileid
);
let
f
=
new
TransferredFile
(
if
(
transferredFiles
[
fullid
])
fileid
,
id
,
true
,
username
,
file
.
name
,
file
.
type
,
file
.
size
,
throw
new
Error
(
'
Id collision
'
);
);
let
f
=
{
f
.
file
=
file
;
id
:
fileid
,
transferredFiles
[
f
.
fullid
()]
=
f
;
username
:
username
,
try
{
file
:
file
,
fileTransferBox
(
f
);
name
:
file
.
name
,
size
:
file
.
size
,
type
:
file
.
type
,
}
fileTransferBox
(
true
,
id
,
fileid
,
f
);
serverConnection
.
userMessage
(
'
offerfile
'
,
id
,
{
serverConnection
.
userMessage
(
'
offerfile
'
,
id
,
{
id
:
fileid
,
id
:
fileid
,
name
:
f
.
name
,
name
:
f
.
name
,
size
:
f
.
size
,
size
:
f
.
size
,
type
:
f
.
type
,
type
:
f
.
type
,
});
});
transferredFiles
[
fullid
]
=
f
;
}
catch
(
e
)
{
displayError
(
e
);
f
.
close
();
}
}
}
/**
/**
* @param {string} id
* @param {TransferredFile} f
* @param {string} fileid
*/
*/
function
cancelFile
(
id
,
fileid
)
{
function
cancelFile
(
f
)
{
let
f
=
getTransferredFile
(
true
,
id
,
fileid
);
serverConnection
.
userMessage
(
'
cancelfile
'
,
f
.
userid
,
{
serverConnection
.
userMessage
(
'
cancelfile
'
,
id
,
{
id
:
f
.
id
,
id
:
f
.
id
,
});
});
deleteTransferredFile
(
true
,
id
,
fileid
);
f
.
close
(
);
setFileStatus
(
true
,
id
,
fileid
,
'
Cancelled.
'
,
true
,
true
);
setFileStatus
(
f
,
'
Cancelled.
'
,
true
,
true
);
}
}
/**
/**
* @param {string} id
* @param {TransferredFile} f
* @param {string} fileid
*/
*/
async
function
getFile
(
id
,
fileid
)
{
async
function
getFile
(
f
)
{
let
f
=
getTransferredFile
(
false
,
id
,
fileid
);
if
(
f
.
pc
)
if
(
f
.
pc
)
throw
new
Error
(
'
Download already in progress
'
);
throw
new
Error
(
"
Download already in progress
"
);
setFileStatus
(
f
,
'
Connecting...
'
,
true
);
setFileStatus
(
false
,
id
,
fileid
,
'
Connecting...
'
,
true
);
let
pc
=
new
RTCPeerConnection
(
serverConnection
.
rtcConfiguration
);
let
pc
=
new
RTCPeerConnection
(
serverConnection
.
rtcConfiguration
);
if
(
!
pc
)
if
(
!
pc
)
throw
new
Error
(
"
Couldn't create peer connection
"
);
throw
new
Error
(
"
Couldn't create peer connection
"
);
...
@@ -2377,75 +2385,71 @@ async function getFile(id, fileid) {
...
@@ -2377,75 +2385,71 @@ async function getFile(id, fileid) {
}
}
};
};
pc
.
onicecandidate
=
function
(
e
)
{
pc
.
onicecandidate
=
function
(
e
)
{
serverConnection
.
userMessage
(
'
filedownice
'
,
id
,
{
serverConnection
.
userMessage
(
'
filedownice
'
,
f
.
user
id
,
{
id
:
f
.
id
,
id
:
f
.
id
,
candidate
:
e
.
candidate
,
candidate
:
e
.
candidate
,
});
});
};
};
let
dc
=
pc
.
createDataChannel
(
'
file
'
);
f
.
dc
=
pc
.
createDataChannel
(
'
file
'
);
f
.
data
=
[];
f
.
data
=
[];
f
.
datalen
=
0
;
f
.
datalen
=
0
;
dc
.
onclose
=
function
(
e
)
{
f
.
dc
.
onclose
=
function
(
e
)
{
try
{
try
{
closeReceiveFileData
(
id
,
fileid
,
f
);
closeReceiveFileData
(
f
);
}
catch
(
e
)
{
}
catch
(
e
)
{
failFile
(
f
alse
,
id
,
fileid
,
e
);
failFile
(
f
,
e
);
}
}
};
};
dc
.
onmessage
=
function
(
e
)
{
f
.
dc
.
onmessage
=
function
(
e
)
{
try
{
try
{
receiveFileData
(
id
,
fileid
,
f
,
dc
,
e
.
data
);
receiveFileData
(
f
,
e
.
data
);
}
catch
(
e
)
{
}
catch
(
e
)
{
failFile
(
f
alse
,
id
,
fileid
,
e
);
failFile
(
f
,
e
);
}
}
};
};
dc
.
onerror
=
function
(
e
)
{
f
.
dc
.
onerror
=
function
(
e
)
{
/** @ts-ignore */
/** @ts-ignore */
let
err
=
e
.
error
;
let
err
=
e
.
error
;
failFile
(
f
alse
,
id
,
fileid
,
err
);
failFile
(
f
,
err
);
};
};
let
offer
=
await
pc
.
createOffer
();
let
offer
=
await
pc
.
createOffer
();
if
(
!
offer
)
if
(
!
offer
)
throw
new
Error
(
"
Couldn't create offer
"
);
throw
new
Error
(
"
Couldn't create offer
"
);
await
pc
.
setLocalDescription
(
offer
);
await
pc
.
setLocalDescription
(
offer
);
serverConnection
.
userMessage
(
'
getfile
'
,
id
,
{
serverConnection
.
userMessage
(
'
getfile
'
,
f
.
user
id
,
{
id
:
f
.
id
,
id
:
f
.
id
,
offer
:
pc
.
localDescription
.
sdp
,
offer
:
pc
.
localDescription
.
sdp
,
});
});
setFileStatus
(
f
alse
,
id
,
fileid
,
'
Negotiating...
'
,
true
);
setFileStatus
(
f
,
'
Negotiating...
'
,
true
);
}
}
/**
/**
* @param {string} id
* @param {TransferredFile} f
* @param {string} fileid
*/
*/
async
function
rejectFile
(
id
,
fileid
)
{
async
function
rejectFile
(
f
)
{
let
f
=
getTransferredFile
(
false
,
id
,
fileid
);
serverConnection
.
userMessage
(
'
rejectfile
'
,
f
.
userid
,
{
serverConnection
.
userMessage
(
'
rejectfile
'
,
id
,
{
id
:
f
.
id
,
id
:
f
.
id
,
});
});
deleteTransferredFile
(
false
,
id
,
fileid
);
setFileStatus
(
f
,
'
Rejected.
'
,
true
,
true
);
setFileStatus
(
false
,
id
,
fileid
,
'
Rejected.
'
,
true
,
true
);
f
.
close
(
);
}
}
/**
/**
* @param {string} id
* @param {TransferredFile} f
* @param {string} fileid
* @param {string} sdp
* @param {string} sdp
*/
*/
async
function
sendFile
(
id
,
fileid
,
sdp
)
{
async
function
sendFile
(
f
,
sdp
)
{
let
f
=
getTransferredFile
(
true
,
id
,
fileid
);
if
(
f
.
pc
)
if
(
f
.
pc
)
throw
new
Error
(
'
Transfer already in progress
'
);
throw
new
Error
(
'
Transfer already in progress
'
);
setFileStatus
(
true
,
id
,
fileid
,
'
Negotiating...
'
,
true
);
setFileStatus
(
f
,
'
Negotiating...
'
,
true
);
let
pc
=
new
RTCPeerConnection
(
serverConnection
.
rtcConfiguration
);
let
pc
=
new
RTCPeerConnection
(
serverConnection
.
rtcConfiguration
);
if
(
!
pc
)
if
(
!
pc
)
throw
new
Error
(
"
Couldn't create peer connection
"
);
throw
new
Error
(
"
Couldn't create peer connection
"
);
f
.
pc
=
pc
;
f
.
pc
=
pc
;
f
.
candidates
=
[];
f
.
candidates
=
[];
pc
.
onicecandidate
=
function
(
e
)
{
pc
.
onicecandidate
=
function
(
e
)
{
serverConnection
.
userMessage
(
'
fileupice
'
,
id
,
{
serverConnection
.
userMessage
(
'
fileupice
'
,
f
.
user
id
,
{
id
:
f
.
id
,
id
:
f
.
id
,
candidate
:
e
.
candidate
,
candidate
:
e
.
candidate
,
});
});
...
@@ -2456,29 +2460,30 @@ async function sendFile(id, fileid, sdp) {
...
@@ -2456,29 +2460,30 @@ async function sendFile(id, fileid, sdp) {
f
.
candidates
=
[];
f
.
candidates
=
[];
}
}
};
};
let
file
=
f
.
file
;
pc
.
ondatachannel
=
function
(
e
)
{
pc
.
ondatachannel
=
function
(
e
)
{
let
dc
=
/** @type{RTCDataChannel} */
(
e
.
channel
);
if
(
f
.
dc
)
dc
.
onclose
=
function
(
e
)
{
throw
new
Error
(
'
Duplicate datachannel
'
);
f
.
dc
=
/** @type{RTCDataChannel} */
(
e
.
channel
);
f
.
dc
.
onclose
=
function
(
e
)
{
try
{
try
{
closeSendFileData
(
id
,
fileid
,
f
);
closeSendFileData
(
f
);
}
catch
(
e
)
{
}
catch
(
e
)
{
failFile
(
true
,
id
,
fileid
,
e
);
failFile
(
f
,
e
);
}
}
};
};
dc
.
onerror
=
function
(
e
)
{
f
.
dc
.
onerror
=
function
(
e
)
{
/** @ts-ignore */
/** @ts-ignore */
let
err
=
e
.
error
;
let
err
=
e
.
error
;
failFile
(
true
,
id
,
fileid
,
err
);
failFile
(
f
,
err
);
}
}
dc
.
onmessage
=
function
(
e
)
{
f
.
dc
.
onmessage
=
function
(
e
)
{
try
{
try
{
ackSendFileData
(
id
,
fileid
,
f
,
e
.
data
);
ackSendFileData
(
f
,
e
.
data
);
}
catch
(
e
)
{
}
catch
(
e
)
{
failFile
(
true
,
id
,
fileid
,
e
);
failFile
(
f
,
e
);
}
}
};
};
sendFileData
(
id
,
fileid
,
f
,
dc
,
file
);
sendFileData
(
f
).
catch
(
e
=>
failFile
(
f
,
e
)
);
};
};
await
pc
.
setRemoteDescription
({
await
pc
.
setRemoteDescription
({
...
@@ -2490,62 +2495,60 @@ async function sendFile(id, fileid, sdp) {
...
@@ -2490,62 +2495,60 @@ async function sendFile(id, fileid, sdp) {
if
(
!
answer
)
if
(
!
answer
)
throw
new
Error
(
"
Couldn't create answer
"
);
throw
new
Error
(
"
Couldn't create answer
"
);
await
pc
.
setLocalDescription
(
answer
);
await
pc
.
setLocalDescription
(
answer
);
serverConnection
.
userMessage
(
'
sendfile
'
,
id
,
{
serverConnection
.
userMessage
(
'
sendfile
'
,
f
.
user
id
,
{
id
:
f
.
id
,
id
:
f
.
id
,
answer
:
pc
.
localDescription
.
sdp
,
answer
:
pc
.
localDescription
.
sdp
,
});
});
setFileStatus
(
true
,
id
,
fileid
,
'
Uploading...
'
,
true
);
setFileStatus
(
f
,
'
Uploading...
'
,
true
);
}
}
/**
/**
* @param {string} id
* @param {TransferredFile} f
* @param {string} fileid
* @param {string} sdp
* @param {string} sdp
*/
*/
async
function
receiveFile
(
id
,
fileid
,
sdp
)
{
async
function
receiveFile
(
f
,
sdp
)
{
let
f
=
getTransferredFile
(
false
,
id
,
fileid
);
if
(
!
f
.
pc
)
throw
new
Error
(
'
Transfer is not in progress
'
);
await
f
.
pc
.
setRemoteDescription
({
await
f
.
pc
.
setRemoteDescription
({
type
:
'
answer
'
,
type
:
'
answer
'
,
sdp
:
sdp
,
sdp
:
sdp
,
});
});
setFileStatus
(
f
alse
,
id
,
fileid
,
'
Downloading...
'
,
true
);
setFileStatus
(
f
,
'
Downloading...
'
,
true
);
}
}
/**
/**
* @param {string} id
* @param {TransferredFile} f
* @param {string} fileid
* @param {transferredFile} f
* @param {RTCDataChannel} dc
* @param {File} file
*/
*/
async
function
sendFileData
(
id
,
fileid
,
f
,
dc
,
file
)
{
async
function
sendFileData
(
f
)
{
let
r
=
file
.
stream
().
getReader
();
let
r
=
f
.
file
.
stream
().
getReader
();
f
.
datalen
=
0
;
dc
.
bufferedAmountLowThreshold
=
65536
;
f
.
dc
.
bufferedAmountLowThreshold
=
65536
;
async
function
write
(
a
)
{
async
function
write
(
a
)
{
while
(
dc
.
bufferedAmount
>
65536
)
{
while
(
f
.
dc
.
bufferedAmount
>
f
.
dc
.
bufferedAmountLowThreshold
)
{
await
new
Promise
((
resolve
,
reject
)
=>
{
await
new
Promise
((
resolve
,
reject
)
=>
{
dc
.
onbufferedamountlow
=
function
(
e
)
{
if
(
f
.
dc
==
null
)
{
reject
(
new
Error
(
'
File is closed.
'
));
}
f
.
dc
.
onbufferedamountlow
=
function
(
e
)
{
if
(
f
.
dc
==
null
)
{
reject
(
new
Error
(
'
File is closed.
'
));
}
f
.
dc
.
onbufferedamountlow
=
null
;
resolve
();
resolve
();
}
}
});
});
}
}
dc
.
send
(
a
);
f
.
dc
.
send
(
a
);
f
.
datalen
+=
a
.
length
;
f
.
datalen
+=
a
.
length
;
setFileStatus
(
setFileStatus
(
f
,
`Uploading...
${
f
.
datalen
}
/
${
f
.
size
}
`
,
true
);
true
,
id
,
fileid
,
`Uploading...
${
f
.
datalen
}
/
${
f
.
size
}
`
,
true
,
);
}
}
while
(
true
)
{
while
(
true
)
{
let
v
=
await
r
.
read
();
let
v
=
await
r
.
read
();
if
(
v
.
done
)
if
(
v
.
done
)
break
;
break
;
if
(
v
.
value
.
length
<
16384
)
{
if
(
!
(
v
.
value
instanceof
Uint8Array
))
throw
new
Error
(
'
Unexpected type for chunk
'
);
if
(
v
.
value
.
length
<=
16384
)
{
await
write
(
v
.
value
);
await
write
(
v
.
value
);
}
else
{
}
else
{
for
(
let
i
=
0
;
i
<
v
.
value
.
length
;
i
+=
16384
)
{
for
(
let
i
=
0
;
i
<
v
.
value
.
length
;
i
+=
16384
)
{
...
@@ -2559,70 +2562,71 @@ async function sendFileData(id, fileid, f, dc, file) {
...
@@ -2559,70 +2562,71 @@ async function sendFileData(id, fileid, f, dc, file) {
}
}
/**
/**
* @param {string} id
* @param {TransferredFile} f
* @param {string} fileid
* @param {transferredFile} f
*/
*/
function
ackSendFileData
(
id
,
fileid
,
f
,
data
)
{
function
ackSendFileData
(
f
,
data
)
{
if
(
data
===
'
done
'
&&
f
.
datalen
==
f
.
size
)
if
(
data
===
'
done
'
&&
f
.
datalen
==
f
.
size
)
setFileStatus
(
true
,
id
,
fileid
,
'
Done.
'
,
true
,
true
);
setFileStatus
(
f
,
'
Done.
'
,
true
,
true
);
else
else
setFileStatus
(
true
,
id
,
fileid
,
'
Failed.
'
,
true
,
true
);
setFileStatus
(
f
,
'
Failed.
'
,
true
,
true
);
f
.
done
=
true
;
f
.
dc
.
onclose
=
null
;
deleteTransferredFile
(
true
,
id
,
fileid
);
f
.
dc
.
onerror
=
null
;
f
.
close
();
}
}
/**
/**
* @param {string} id
* @param {TransferredFile} f
* @param {string} fileid
* @param {transferredFile} f
*/
*/
function
closeSendFileData
(
id
,
fileid
,
f
)
{
function
closeSendFileData
(
f
)
{
if
(
!
f
.
done
)
setFileStatus
(
f
,
'
Failed.
'
,
true
,
true
);
setFileStatus
(
true
,
id
,
fileid
,
'
Failed.
'
,
true
,
true
);
f
.
close
();
deleteTransferredFile
(
true
,
id
,
fileid
);
}
}
/**
/**
* @param {string} id
* @param {TransferredFile} f
* @param {string} fileid
* @param {transferredFile} f
* @param {RTCDataChannel} dc
* @param {Blob|ArrayBuffer} data
* @param {Blob|ArrayBuffer} data
*/
*/
function
receiveFileData
(
id
,
fileid
,
f
,
dc
,
data
)
{
function
receiveFileData
(
f
,
data
)
{
f
.
data
.
push
(
data
);
f
.
pushData
(
data
);
if
(
data
instanceof
Blob
)
{
setFileStatus
(
f
,
`Downloading...
${
f
.
datalen
}
/
${
f
.
size
}
`
,
true
);
f
.
datalen
+=
data
.
size
;
}
else
if
(
data
instanceof
ArrayBuffer
)
{
f
.
datalen
+=
data
.
byteLength
;
}
else
{
console
.
error
(
'
Unexpeced type for received data
'
,
data
);
throw
new
Error
(
'
unexpected type for received data
'
);
}
setFileStatus
(
false
,
id
,
fileid
,
`Downloading...
${
f
.
datalen
}
/
${
f
.
size
}
`
,
true
,
);
if
(
f
.
datalen
<
f
.
size
)
if
(
f
.
datalen
<
f
.
size
)
return
;
return
;
if
(
f
.
datalen
>
f
.
size
)
{
if
(
f
.
datalen
!=
f
.
size
)
{
setFileStatus
(
f
alse
,
id
,
fileid
,
'
Failed.
'
,
true
,
true
);
setFileStatus
(
f
,
'
Failed.
'
,
true
,
true
);
deleteTransferredFile
(
false
,
id
,
fileid
);
f
.
close
(
);
return
;
return
;
}
}
dc
.
onmessage
=
null
;
f
.
dc
.
onmessage
=
null
;
dc
.
onerror
=
null
;
doneReceiveFileData
(
f
);
}
dc
.
send
(
'
done
'
);
/**
* @param {TransferredFile} f
*/
async
function
doneReceiveFileData
(
f
)
{
setFileStatus
(
f
,
'
Done.
'
,
true
,
true
);
let
blob
=
f
.
getData
();
setFileStatus
(
false
,
id
,
fileid
,
'
Done.
'
,
true
,
true
);
await
new
Promise
((
resolve
,
reject
)
=>
{
let
timer
=
setTimeout
(
function
(
e
)
{
resolve
();
},
2000
);
f
.
dc
.
onclose
=
function
(
e
)
{
clearTimeout
(
timer
);
resolve
();
};
f
.
dc
.
onerror
=
function
(
e
)
{
clearTimeout
(
timer
);
resolve
();
};
f
.
dc
.
send
(
'
done
'
);
});
f
.
dc
.
onclose
=
null
;
f
.
dc
.
onerror
=
null
;
f
.
close
();
let
blob
=
new
Blob
(
f
.
data
,
{
type
:
f
.
type
});
f
.
data
=
null
;
let
url
=
URL
.
createObjectURL
(
blob
);
let
url
=
URL
.
createObjectURL
(
blob
);
let
a
=
document
.
createElement
(
'
a
'
);
let
a
=
document
.
createElement
(
'
a
'
);
a
.
href
=
url
;
a
.
href
=
url
;
...
@@ -2634,14 +2638,12 @@ function receiveFileData(id, fileid, f, dc, data) {
...
@@ -2634,14 +2638,12 @@ function receiveFileData(id, fileid, f, dc, data) {
}
}
/**
/**
* @param {string} id
* @param {TransferredFile} f
* @param {string} fileid
* @param {transferredFile} f
*/
*/
function
closeReceiveFileData
(
id
,
fileid
,
f
)
{
function
closeReceiveFileData
(
f
)
{
if
(
f
.
datalen
!=
f
.
size
)
{
if
(
f
.
datalen
!=
f
.
size
)
{
setFileStatus
(
f
alse
,
id
,
fileid
,
'
Failed.
'
,
true
,
true
)
setFileStatus
(
f
,
'
Failed.
'
,
true
,
true
)
deleteTransferredFile
(
false
,
id
,
fileid
);
f
.
close
(
);
}
}
}
}
...
@@ -2683,38 +2685,46 @@ function gotUserMessage(id, dest, username, time, privileged, kind, message) {
...
@@ -2683,38 +2685,46 @@ function gotUserMessage(id, dest, username, time, privileged, kind, message) {
}
}
break
;
break
;
case
'
offerfile
'
:
{
case
'
offerfile
'
:
{
let
fullid
=
transferredFileId
(
false
,
id
,
message
.
id
);
let
f
=
new
TransferredFile
(
let
f
=
{
message
.
id
,
id
,
false
,
username
,
id
:
message
.
id
,
message
.
name
,
message
.
type
,
message
.
size
,
username
:
username
,
);
name
:
message
.
name
,
transferredFiles
[
f
.
fullid
()]
=
f
;
type
:
message
.
type
,
fileTransferBox
(
f
);
size
:
message
.
size
,
};
transferredFiles
[
fullid
]
=
f
;
fileTransferBox
(
false
,
id
,
message
.
id
,
f
);
break
;
break
;
}
}
case
'
cancelfile
'
:
{
case
'
cancelfile
'
:
{
setFileStatus
(
false
,
id
,
message
.
id
,
'
Cancelled.
'
,
true
,
true
);
let
f
=
TransferredFile
.
get
(
false
,
id
,
message
.
id
);
deleteTransferredFile
(
false
,
id
,
message
.
id
);
if
(
!
f
)
throw
new
Error
(
'
unexpected cancelfile
'
);
setFileStatus
(
f
,
'
Cancelled.
'
,
true
,
true
);
f
.
close
();
break
;
break
;
}
}
case
'
getfile
'
:
{
case
'
getfile
'
:
{
sendFile
(
id
,
message
.
id
,
message
.
offer
);
let
f
=
TransferredFile
.
get
(
true
,
id
,
message
.
id
);
if
(
!
f
)
throw
new
Error
(
'
unexpected getfile
'
);
sendFile
(
f
,
message
.
offer
);
break
;
break
;
}
}
case
'
rejectfile
'
:
{
case
'
rejectfile
'
:
{
setFileStatus
(
true
,
id
,
message
.
id
,
'
Rejected.
'
,
true
,
true
);
let
f
=
TransferredFile
.
get
(
true
,
id
,
message
.
id
);
deleteTransferredFile
(
true
,
id
,
message
.
id
);
if
(
!
f
)
throw
new
Error
(
'
unexpected rejectfile
'
);
setFileStatus
(
f
,
'
Rejected.
'
,
true
,
true
);
f
.
close
();
break
;
break
;
}
}
case
'
sendfile
'
:
{
case
'
sendfile
'
:
{
receiveFile
(
id
,
message
.
id
,
message
.
answer
);
let
f
=
TransferredFile
.
get
(
false
,
id
,
message
.
id
);
if
(
!
f
)
throw
new
Error
(
'
unexpected sendfile
'
);
receiveFile
(
f
,
message
.
answer
);
break
;
break
;
}
}
case
'
filedownice
'
:
{
case
'
filedownice
'
:
{
let
f
=
getTransferredFile
(
true
,
id
,
message
.
id
);
let
f
=
TransferredFile
.
get
(
true
,
id
,
message
.
id
);
if
(
!
f
.
pc
)
{
if
(
!
f
.
pc
)
{
console
.
warn
(
'
Unexpected filedownice
'
);
console
.
warn
(
'
Unexpected filedownice
'
);
return
;
return
;
...
@@ -2726,7 +2736,7 @@ function gotUserMessage(id, dest, username, time, privileged, kind, message) {
...
@@ -2726,7 +2736,7 @@ function gotUserMessage(id, dest, username, time, privileged, kind, message) {
break
;
break
;
}
}
case
'
fileupice
'
:
{
case
'
fileupice
'
:
{
let
f
=
getTransferredFile
(
false
,
id
,
message
.
id
);
let
f
=
TransferredFile
.
get
(
false
,
id
,
message
.
id
);
if
(
!
f
.
pc
)
{
if
(
!
f
.
pc
)
{
console
.
warn
(
'
Unexpected fileupice
'
);
console
.
warn
(
'
Unexpected fileupice
'
);
return
;
return
;
...
@@ -3279,7 +3289,7 @@ commands.sendfile = {
...
@@ -3279,7 +3289,7 @@ commands.sendfile = {
let
files
=
input
.
files
;
let
files
=
input
.
files
;
for
(
let
i
=
0
;
i
<
files
.
length
;
i
++
)
{
for
(
let
i
=
0
;
i
<
files
.
length
;
i
++
)
{
try
{
try
{
offerFile
(
p
[
0
],
id
,
files
[
i
]);
offerFile
(
p
[
i
],
id
,
files
[
i
]);
}
catch
(
e
)
{
}
catch
(
e
)
{
console
.
error
(
e
);
console
.
error
(
e
);
displayError
(
e
);
displayError
(
e
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment