Compare commits
2 Commits
f543cc642e
...
resolve
Author | SHA1 | Date | |
---|---|---|---|
e55548b105 | |||
cea3f7e33c |
@ -10,6 +10,6 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- run: sudo apt update && sudo apt install -y doxygen graphviz mingw-w64
|
- run: sudo apt update && sudo apt install -y doxygen mingw-w64
|
||||||
- run: make all -j`nproc` docs
|
- run: make all -j`nproc` docs
|
||||||
- run: docker build .
|
- run: docker build .
|
||||||
|
19
GNUmakefile
19
GNUmakefile
@ -7,7 +7,7 @@ VERSION_CODE := 26
|
|||||||
VERSION_NUMBER := 0.0.22-wip
|
VERSION_NUMBER := 0.0.22-wip
|
||||||
VERSION_NAME := Look for the helpers.
|
VERSION_NAME := Look for the helpers.
|
||||||
|
|
||||||
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3460100.zip
|
SQLITE_URL := https://www.sqlite.org/2024/sqlite-amalgamation-3460000.zip
|
||||||
LIBUV_URL := https://dist.libuv.org/dist/v1.48.0/libuv-v1.48.0.tar.gz
|
LIBUV_URL := https://dist.libuv.org/dist/v1.48.0/libuv-v1.48.0.tar.gz
|
||||||
BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.17.0/bundletool-all-1.17.0.jar
|
BUNDLETOOL_URL := https://github.com/google/bundletool/releases/download/1.17.0/bundletool-all-1.17.0.jar
|
||||||
|
|
||||||
@ -60,10 +60,11 @@ CFLAGS += \
|
|||||||
-ffunction-sections \
|
-ffunction-sections \
|
||||||
-fdata-sections \
|
-fdata-sections \
|
||||||
-fno-exceptions \
|
-fno-exceptions \
|
||||||
-g
|
-g \
|
||||||
|
-flto
|
||||||
LDFLAGS += \
|
LDFLAGS += \
|
||||||
-Wno-attributes \
|
-flto=auto \
|
||||||
-flto=auto
|
-Wno-attributes
|
||||||
|
|
||||||
ANDROID_MIN_SDK_VERSION := 24
|
ANDROID_MIN_SDK_VERSION := 24
|
||||||
ANDROID_TARGET_SDK_VERSION := 34
|
ANDROID_TARGET_SDK_VERSION := 34
|
||||||
@ -168,13 +169,10 @@ $(ANDROID_TARGETS): CFLAGS += \
|
|||||||
-fdebug-compilation-dir . \
|
-fdebug-compilation-dir . \
|
||||||
-fomit-frame-pointer \
|
-fomit-frame-pointer \
|
||||||
-fno-asynchronous-unwind-tables \
|
-fno-asynchronous-unwind-tables \
|
||||||
-funwind-tables \
|
-funwind-tables
|
||||||
-Wno-unknown-warning-option
|
|
||||||
$(ANDROID_TARGETS): LDFLAGS += --sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC
|
$(ANDROID_TARGETS): LDFLAGS += --sysroot $(ANDROID_NDK)/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC
|
||||||
$(DEBUG_TARGETS): CFLAGS += -DDEBUG -Og
|
$(DEBUG_TARGETS): CFLAGS += -DDEBUG -Og
|
||||||
$(RELEASE_TARGETS): CFLAGS += \
|
$(RELEASE_TARGETS): CFLAGS += -DNDEBUG
|
||||||
-DNDEBUG \
|
|
||||||
-flto
|
|
||||||
$(NONANDROID_RELEASE_TARGETS): CFLAGS += -O3
|
$(NONANDROID_RELEASE_TARGETS): CFLAGS += -O3
|
||||||
$(ANDROID_RELEASE_TARGETS): CFLAGS += -Oz
|
$(ANDROID_RELEASE_TARGETS): CFLAGS += -Oz
|
||||||
$(WINDOWS_TARGETS): CC = x86_64-w64-mingw32-gcc-win32
|
$(WINDOWS_TARGETS): CC = x86_64-w64-mingw32-gcc-win32
|
||||||
@ -500,7 +498,6 @@ $(UV_OBJS): CFLAGS += \
|
|||||||
-Wno-unused-but-set-variable \
|
-Wno-unused-but-set-variable \
|
||||||
-Wno-unused-result \
|
-Wno-unused-result \
|
||||||
-Wno-unused-variable
|
-Wno-unused-variable
|
||||||
$(UV_OBJS): CFLAGS := $(filter-out -flto,$(CFLAGS))
|
|
||||||
ifeq ($(UNAME_S),Linux)
|
ifeq ($(UNAME_S),Linux)
|
||||||
$(UV_OBJS): CFLAGS += \
|
$(UV_OBJS): CFLAGS += \
|
||||||
-D_GNU_SOURCE
|
-D_GNU_SOURCE
|
||||||
@ -1126,4 +1123,4 @@ docs:
|
|||||||
.PHONY: docs
|
.PHONY: docs
|
||||||
|
|
||||||
fdroid: out/apk/TildeFriends-release.fdroid.unsigned.apk
|
fdroid: out/apk/TildeFriends-release.fdroid.unsigned.apk
|
||||||
.PHONY: fdroid
|
.PHONE: fdroid
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"type": "tildefriends-app",
|
"type": "tildefriends-app",
|
||||||
"emoji": "🐌",
|
"emoji": "🐌",
|
||||||
"previous": "&xsmsLytB3VvoHphiFHZGGEvrCfTEVGXrGwobGTIYFPQ=.sha256"
|
"previous": "&2xK//SIpjFb0+uT5I7MSAGJ3d1FKuI/rlzhcCQd3NME=.sha256"
|
||||||
}
|
}
|
||||||
|
@ -188,10 +188,6 @@ class TfProfileElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_id() {
|
|
||||||
navigator.clipboard.writeText(this.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (
|
if (
|
||||||
this.id == this.whoami &&
|
this.id == this.whoami &&
|
||||||
@ -291,14 +287,6 @@ class TfProfileElement extends LitElement {
|
|||||||
let description = this.editing?.description ?? profile.description;
|
let description = this.editing?.description ?? profile.description;
|
||||||
return html`<div style="border: 2px solid black; background-color: rgba(255, 255, 255, 0.2); padding: 16px">
|
return html`<div style="border: 2px solid black; background-color: rgba(255, 255, 255, 0.2); padding: 16px">
|
||||||
<tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)})
|
<tf-user id=${this.id} .users=${this.users}></tf-user> (${tfutils.human_readable_size(this.size)})
|
||||||
<div class="w3-row">
|
|
||||||
<div class="w3-col s1 w3-container w3-right">
|
|
||||||
<button class="w3-button w3-theme-d1 w3-ripple" @click=${this.copy_id}>Copy</button>
|
|
||||||
</div>
|
|
||||||
<div class="w3-rest w3-container">
|
|
||||||
<input type="text" class="w3-theme-d1" style="width: 100%; vertical-align: middle" readonly value=${this.id}></input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style="display: flex; flex-direction: row; gap: 1em">
|
<div style="display: flex; flex-direction: row; gap: 1em">
|
||||||
${edit_profile}
|
${edit_profile}
|
||||||
<div style="flex: 1 0 50%">
|
<div style="flex: 1 0 50%">
|
||||||
|
@ -17,12 +17,6 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
|
|
||||||
static styles = styles;
|
static styles = styles;
|
||||||
|
|
||||||
static k_broadcast_emojis = {
|
|
||||||
discovery: '🏓',
|
|
||||||
room: '🚪',
|
|
||||||
peer_exchange: '🕸',
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
let self = this;
|
let self = this;
|
||||||
@ -98,7 +92,6 @@ class TfTabConnectionsElement extends LitElement {
|
|||||||
Connect
|
Connect
|
||||||
</button>
|
</button>
|
||||||
<div class="w3-bar-item">
|
<div class="w3-bar-item">
|
||||||
${TfTabConnectionsElement.k_broadcast_emojis[connection.origin]}
|
|
||||||
<tf-user id=${connection.pubkey} .users=${this.users}></tf-user>
|
<tf-user id=${connection.pubkey} .users=${this.users}></tf-user>
|
||||||
${this.render_connection_summary(connection)}
|
${this.render_connection_summary(connection)}
|
||||||
</div>
|
</div>
|
||||||
|
19
core/core.js
19
core/core.js
@ -23,18 +23,13 @@ const k_global_settings = {
|
|||||||
room: {
|
room: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
default_value: true,
|
default_value: true,
|
||||||
description: 'Enable peers to tunnel through this instance as a room.',
|
description: 'Whether this instance should behave as a room.',
|
||||||
},
|
},
|
||||||
room_name: {
|
room_name: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default_value: 'tilde friends tunnel',
|
default_value: 'tilde friends tunnel',
|
||||||
description: 'Name of the room.',
|
description: 'Name of the room.',
|
||||||
},
|
},
|
||||||
replicator: {
|
|
||||||
type: 'boolean',
|
|
||||||
default_value: true,
|
|
||||||
description: 'Enable message and blob replication.',
|
|
||||||
},
|
|
||||||
code_of_conduct: {
|
code_of_conduct: {
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
default_value: undefined,
|
default_value: undefined,
|
||||||
@ -71,19 +66,9 @@ const k_global_settings = {
|
|||||||
},
|
},
|
||||||
seeds_host: {
|
seeds_host: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default_value: 'seeds.tildefriends.net',
|
default_value: '',
|
||||||
description: 'Hostname for seed connections.',
|
description: 'Hostname for seed connections.',
|
||||||
},
|
},
|
||||||
peer_exchange: {
|
|
||||||
type: 'boolean',
|
|
||||||
default_value: false,
|
|
||||||
description: 'Enable discovery of, sharing of, and connecting to internet peer strangers, including announcing this instance.',
|
|
||||||
},
|
|
||||||
account_registration: {
|
|
||||||
type: 'boolean',
|
|
||||||
default_value: true,
|
|
||||||
description: 'Allow registration of new accounts.',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let gGlobalSettings = {
|
let gGlobalSettings = {
|
||||||
|
17
deps/c-ares_config/ares_build.h
vendored
17
deps/c-ares_config/ares_build.h
vendored
@ -34,27 +34,26 @@
|
|||||||
#define CARES_TYPEOF_ARES_SSIZE_T ssize_t
|
#define CARES_TYPEOF_ARES_SSIZE_T ssize_t
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__OpenBSD__)
|
#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__OpenBSD__) && !defined(__HAIKU__)
|
||||||
#define GETSERVBYNAME_R_ARGS 6
|
#define GETSERVBYNAME_R_ARGS 6
|
||||||
#define GETSERVBYPORT_R_ARGS 6
|
#define GETSERVBYPORT_R_ARGS 6
|
||||||
#define HAVE_GETSERVBYNAME_R 1
|
#define HAVE_GETSERVBYNAME_R 1
|
||||||
#define HAVE_GETSERVBYPORT_R 1
|
#define HAVE_GETSERVBYPORT_R 1
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__OpenBSD__)
|
|
||||||
#define HAVE_PIPE2 1
|
#define HAVE_PIPE2 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__OpenBSD__)
|
#if defined(__OpenBSD__) || defined(__HAIKU__)
|
||||||
#define GETSERVBYNAME_R_ARGS 4
|
#define GETSERVBYNAME_R_ARGS 4
|
||||||
#define GETSERVBYPORT_R_ARGS 4
|
#define GETSERVBYPORT_R_ARGS 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__OpenBSD__)
|
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__OpenBSD__)
|
||||||
#define HAVE_MALLOC_H 1
|
#define HAVE_MALLOC_H 1
|
||||||
|
#if !defined(__HAIKU__)
|
||||||
|
#define HAVE_SYS_RANDOM_H 1
|
||||||
#define HAVE_EPOLL 1
|
#define HAVE_EPOLL 1
|
||||||
#define HAVE_SYS_EPOLL_H 1
|
#define HAVE_SYS_EPOLL_H 1
|
||||||
#define HAVE_SYS_RANDOM_H 1
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(__WIN32)
|
#if !defined(__WIN32)
|
||||||
@ -86,7 +85,9 @@
|
|||||||
#define HAVE_GETENV 1
|
#define HAVE_GETENV 1
|
||||||
#define HAVE_GETHOSTNAME 1
|
#define HAVE_GETHOSTNAME 1
|
||||||
#define HAVE_GETNAMEINFO 1
|
#define HAVE_GETNAMEINFO 1
|
||||||
|
#if !defined(__HAIKU__)
|
||||||
#define HAVE_GETRANDOM 1
|
#define HAVE_GETRANDOM 1
|
||||||
|
#endif
|
||||||
#define HAVE_GETTIMEOFDAY 1
|
#define HAVE_GETTIMEOFDAY 1
|
||||||
#define HAVE_IF_INDEXTONAME 1
|
#define HAVE_IF_INDEXTONAME 1
|
||||||
#define HAVE_IF_NAMETOINDEX 1
|
#define HAVE_IF_NAMETOINDEX 1
|
||||||
@ -137,10 +138,8 @@
|
|||||||
#define HAVE_IFADDRS_H 1
|
#define HAVE_IFADDRS_H 1
|
||||||
#define HAVE_UNISTD_H 1
|
#define HAVE_UNISTD_H 1
|
||||||
#define HAVE_WRITEV 1
|
#define HAVE_WRITEV 1
|
||||||
#if defined(__ANDROID__) || defined(__APPLE__) || defined(__OpenBSD__)
|
#if !defined(__HAIKU__)
|
||||||
#define HAVE_ARC4RANDOM_BUF 1
|
#define HAVE_ARC4RANDOM_BUF 1
|
||||||
#else
|
|
||||||
#undef HAVE_ARC4RANDOM_BUF
|
|
||||||
#endif
|
#endif
|
||||||
#define HAVE_GETIFADDRS 1
|
#define HAVE_GETIFADDRS 1
|
||||||
#define HAVE_STAT 1
|
#define HAVE_STAT 1
|
||||||
|
40
deps/sqlite/shell.c
vendored
40
deps/sqlite/shell.c
vendored
@ -604,6 +604,11 @@ zSkipValidUtf8(const char *z, int nAccept, long ccm);
|
|||||||
# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
|
# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CIO_WIN_WC_XLATE
|
||||||
|
/* Character used to represent a known-incomplete UTF-8 char group (<28>) */
|
||||||
|
static WCHAR cBadGroup = 0xfffd;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CIO_WIN_WC_XLATE
|
#if CIO_WIN_WC_XLATE
|
||||||
static HANDLE handleOfFile(FILE *pf){
|
static HANDLE handleOfFile(FILE *pf){
|
||||||
int fileDesc = _fileno(pf);
|
int fileDesc = _fileno(pf);
|
||||||
@ -12542,7 +12547,7 @@ static int expertFilter(
|
|||||||
pCsr->pData = 0;
|
pCsr->pData = 0;
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = idxPrintfPrepareStmt(pExpert->db, &pCsr->pData, &pVtab->base.zErrMsg,
|
rc = idxPrintfPrepareStmt(pExpert->db, &pCsr->pData, &pVtab->base.zErrMsg,
|
||||||
"SELECT * FROM main.%Q WHERE sqlite_expert_sample()", pVtab->pTab->zName
|
"SELECT * FROM main.%Q WHERE sample()", pVtab->pTab->zName
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13416,7 +13421,7 @@ struct IdxRemCtx {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Implementation of scalar function sqlite_expert_rem().
|
** Implementation of scalar function rem().
|
||||||
*/
|
*/
|
||||||
static void idxRemFunc(
|
static void idxRemFunc(
|
||||||
sqlite3_context *pCtx,
|
sqlite3_context *pCtx,
|
||||||
@ -13429,7 +13434,7 @@ static void idxRemFunc(
|
|||||||
assert( argc==2 );
|
assert( argc==2 );
|
||||||
|
|
||||||
iSlot = sqlite3_value_int(argv[0]);
|
iSlot = sqlite3_value_int(argv[0]);
|
||||||
assert( iSlot<p->nSlot );
|
assert( iSlot<=p->nSlot );
|
||||||
pSlot = &p->aSlot[iSlot];
|
pSlot = &p->aSlot[iSlot];
|
||||||
|
|
||||||
switch( pSlot->eType ){
|
switch( pSlot->eType ){
|
||||||
@ -13540,8 +13545,7 @@ static int idxPopulateOneStat1(
|
|||||||
const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
|
const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
|
||||||
const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
|
const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
|
||||||
zCols = idxAppendText(&rc, zCols,
|
zCols = idxAppendText(&rc, zCols,
|
||||||
"%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s",
|
"%sx.%Q IS rem(%d, x.%Q) COLLATE %s", zComma, zName, nCol, zName, zColl
|
||||||
zComma, zName, nCol, zName, zColl
|
|
||||||
);
|
);
|
||||||
zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
|
zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
|
||||||
}
|
}
|
||||||
@ -13674,13 +13678,13 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
|
|||||||
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
|
sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
|
||||||
rc = sqlite3_create_function(dbrem, "sqlite_expert_rem",
|
rc = sqlite3_create_function(
|
||||||
2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0
|
dbrem, "rem", 2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3_create_function(p->db, "sqlite_expert_sample",
|
rc = sqlite3_create_function(
|
||||||
0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0
|
p->db, "sample", 0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13732,9 +13736,6 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
|
|||||||
rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
|
rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_create_function(p->db, "sqlite_expert_rem", 2, SQLITE_UTF8, 0,0,0,0);
|
|
||||||
sqlite3_create_function(p->db, "sqlite_expert_sample", 0,SQLITE_UTF8,0,0,0,0);
|
|
||||||
|
|
||||||
sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
|
sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -16835,8 +16836,8 @@ static int recoverError(
|
|||||||
va_start(ap, zFmt);
|
va_start(ap, zFmt);
|
||||||
if( zFmt ){
|
if( zFmt ){
|
||||||
z = sqlite3_vmprintf(zFmt, ap);
|
z = sqlite3_vmprintf(zFmt, ap);
|
||||||
|
va_end(ap);
|
||||||
}
|
}
|
||||||
va_end(ap);
|
|
||||||
sqlite3_free(p->zErrMsg);
|
sqlite3_free(p->zErrMsg);
|
||||||
p->zErrMsg = z;
|
p->zErrMsg = z;
|
||||||
p->errCode = errCode;
|
p->errCode = errCode;
|
||||||
@ -27084,6 +27085,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|||||||
import_cleanup(&sCtx);
|
import_cleanup(&sCtx);
|
||||||
shell_out_of_memory();
|
shell_out_of_memory();
|
||||||
}
|
}
|
||||||
|
nByte = strlen(zSql);
|
||||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
|
||||||
sqlite3_free(zSql);
|
sqlite3_free(zSql);
|
||||||
zSql = 0;
|
zSql = 0;
|
||||||
@ -27102,21 +27104,16 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|||||||
sqlite3_finalize(pStmt);
|
sqlite3_finalize(pStmt);
|
||||||
pStmt = 0;
|
pStmt = 0;
|
||||||
if( nCol==0 ) return 0; /* no columns, no error */
|
if( nCol==0 ) return 0; /* no columns, no error */
|
||||||
|
zSql = sqlite3_malloc64( nByte*2 + 20 + nCol*2 );
|
||||||
nByte = 64 /* space for "INSERT INTO", "VALUES(", ")\0" */
|
|
||||||
+ (zSchema ? strlen(zSchema)*2 + 2: 0) /* Quoted schema name */
|
|
||||||
+ strlen(zTable)*2 + 2 /* Quoted table name */
|
|
||||||
+ nCol*2; /* Space for ",?" for each column */
|
|
||||||
zSql = sqlite3_malloc64( nByte );
|
|
||||||
if( zSql==0 ){
|
if( zSql==0 ){
|
||||||
import_cleanup(&sCtx);
|
import_cleanup(&sCtx);
|
||||||
shell_out_of_memory();
|
shell_out_of_memory();
|
||||||
}
|
}
|
||||||
if( zSchema ){
|
if( zSchema ){
|
||||||
sqlite3_snprintf(nByte, zSql, "INSERT INTO \"%w\".\"%w\" VALUES(?",
|
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\".\"%w\" VALUES(?",
|
||||||
zSchema, zTable);
|
zSchema, zTable);
|
||||||
}else{
|
}else{
|
||||||
sqlite3_snprintf(nByte, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
|
sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable);
|
||||||
}
|
}
|
||||||
j = strlen30(zSql);
|
j = strlen30(zSql);
|
||||||
for(i=1; i<nCol; i++){
|
for(i=1; i<nCol; i++){
|
||||||
@ -27125,7 +27122,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
|||||||
}
|
}
|
||||||
zSql[j++] = ')';
|
zSql[j++] = ')';
|
||||||
zSql[j] = 0;
|
zSql[j] = 0;
|
||||||
assert( j<nByte );
|
|
||||||
if( eVerbose>=2 ){
|
if( eVerbose>=2 ){
|
||||||
oputf("Insert using: %s\n", zSql);
|
oputf("Insert using: %s\n", zSql);
|
||||||
}
|
}
|
||||||
|
154
deps/sqlite/sqlite3.c
vendored
154
deps/sqlite/sqlite3.c
vendored
@ -1,6 +1,6 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
** This file is an amalgamation of many separate C source files from SQLite
|
** This file is an amalgamation of many separate C source files from SQLite
|
||||||
** version 3.46.1. By combining all the individual C code files into this
|
** version 3.46.0. By combining all the individual C code files into this
|
||||||
** single large file, the entire code can be compiled as a single translation
|
** single large file, the entire code can be compiled as a single translation
|
||||||
** unit. This allows many compilers to do optimizations that would not be
|
** unit. This allows many compilers to do optimizations that would not be
|
||||||
** possible if the files were compiled separately. Performance improvements
|
** possible if the files were compiled separately. Performance improvements
|
||||||
@ -18,7 +18,7 @@
|
|||||||
** separate file. This file contains only code for the core SQLite library.
|
** separate file. This file contains only code for the core SQLite library.
|
||||||
**
|
**
|
||||||
** The content in this amalgamation comes from Fossil check-in
|
** The content in this amalgamation comes from Fossil check-in
|
||||||
** c9c2ab54ba1f5f46360f1b4f35d849cd3f08.
|
** 96c92aba00c8375bc32fafcdf12429c58bd8.
|
||||||
*/
|
*/
|
||||||
#define SQLITE_CORE 1
|
#define SQLITE_CORE 1
|
||||||
#define SQLITE_AMALGAMATION 1
|
#define SQLITE_AMALGAMATION 1
|
||||||
@ -459,9 +459,9 @@ extern "C" {
|
|||||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||||
** [sqlite_version()] and [sqlite_source_id()].
|
** [sqlite_version()] and [sqlite_source_id()].
|
||||||
*/
|
*/
|
||||||
#define SQLITE_VERSION "3.46.1"
|
#define SQLITE_VERSION "3.46.0"
|
||||||
#define SQLITE_VERSION_NUMBER 3046001
|
#define SQLITE_VERSION_NUMBER 3046000
|
||||||
#define SQLITE_SOURCE_ID "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33"
|
#define SQLITE_SOURCE_ID "2024-05-23 13:25:27 96c92aba00c8375bc32fafcdf12429c58bd8aabfcadab6683e35bbb9cdebf19e"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Run-Time Library Version Numbers
|
** CAPI3REF: Run-Time Library Version Numbers
|
||||||
@ -19361,7 +19361,7 @@ struct SrcList {
|
|||||||
#define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */
|
#define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */
|
||||||
#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */
|
#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */
|
||||||
#define WHERE_RIGHT_JOIN 0x1000 /* Processing a RIGHT JOIN */
|
#define WHERE_RIGHT_JOIN 0x1000 /* Processing a RIGHT JOIN */
|
||||||
#define WHERE_KEEP_ALL_JOINS 0x2000 /* Do not do the omit-noop-join opt */
|
/* 0x2000 not currently used */
|
||||||
#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */
|
#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */
|
||||||
/* 0x8000 not currently used */
|
/* 0x8000 not currently used */
|
||||||
|
|
||||||
@ -90173,8 +90173,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff
|
|||||||
assert( iVar>0 );
|
assert( iVar>0 );
|
||||||
if( v ){
|
if( v ){
|
||||||
Mem *pMem = &v->aVar[iVar-1];
|
Mem *pMem = &v->aVar[iVar-1];
|
||||||
assert( (v->db->flags & SQLITE_EnableQPSG)==0
|
assert( (v->db->flags & SQLITE_EnableQPSG)==0 );
|
||||||
|| (v->db->mDbFlags & DBFLAG_InternalFunc)!=0 );
|
|
||||||
if( 0==(pMem->flags & MEM_Null) ){
|
if( 0==(pMem->flags & MEM_Null) ){
|
||||||
sqlite3_value *pRet = sqlite3ValueNew(v->db);
|
sqlite3_value *pRet = sqlite3ValueNew(v->db);
|
||||||
if( pRet ){
|
if( pRet ){
|
||||||
@ -90194,8 +90193,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff
|
|||||||
*/
|
*/
|
||||||
SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
|
SQLITE_PRIVATE void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
|
||||||
assert( iVar>0 );
|
assert( iVar>0 );
|
||||||
assert( (v->db->flags & SQLITE_EnableQPSG)==0
|
assert( (v->db->flags & SQLITE_EnableQPSG)==0 );
|
||||||
|| (v->db->mDbFlags & DBFLAG_InternalFunc)!=0 );
|
|
||||||
if( iVar>=32 ){
|
if( iVar>=32 ){
|
||||||
v->expmask |= 0x80000000;
|
v->expmask |= 0x80000000;
|
||||||
}else{
|
}else{
|
||||||
@ -106952,7 +106950,7 @@ static void extendFJMatch(
|
|||||||
static SQLITE_NOINLINE int isValidSchemaTableName(
|
static SQLITE_NOINLINE int isValidSchemaTableName(
|
||||||
const char *zTab, /* Name as it appears in the SQL */
|
const char *zTab, /* Name as it appears in the SQL */
|
||||||
Table *pTab, /* The schema table we are trying to match */
|
Table *pTab, /* The schema table we are trying to match */
|
||||||
const char *zDb /* non-NULL if a database qualifier is present */
|
Schema *pSchema /* non-NULL if a database qualifier is present */
|
||||||
){
|
){
|
||||||
const char *zLegacy;
|
const char *zLegacy;
|
||||||
assert( pTab!=0 );
|
assert( pTab!=0 );
|
||||||
@ -106963,7 +106961,7 @@ static SQLITE_NOINLINE int isValidSchemaTableName(
|
|||||||
if( sqlite3StrICmp(zTab+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){
|
if( sqlite3StrICmp(zTab+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if( zDb==0 ) return 0;
|
if( pSchema==0 ) return 0;
|
||||||
if( sqlite3StrICmp(zTab+7, &LEGACY_SCHEMA_TABLE[7])==0 ) return 1;
|
if( sqlite3StrICmp(zTab+7, &LEGACY_SCHEMA_TABLE[7])==0 ) return 1;
|
||||||
if( sqlite3StrICmp(zTab+7, &PREFERRED_SCHEMA_TABLE[7])==0 ) return 1;
|
if( sqlite3StrICmp(zTab+7, &PREFERRED_SCHEMA_TABLE[7])==0 ) return 1;
|
||||||
}else{
|
}else{
|
||||||
@ -107146,7 +107144,7 @@ static int lookupName(
|
|||||||
}
|
}
|
||||||
}else if( sqlite3StrICmp(zTab, pTab->zName)!=0 ){
|
}else if( sqlite3StrICmp(zTab, pTab->zName)!=0 ){
|
||||||
if( pTab->tnum!=1 ) continue;
|
if( pTab->tnum!=1 ) continue;
|
||||||
if( !isValidSchemaTableName(zTab, pTab, zDb) ) continue;
|
if( !isValidSchemaTableName(zTab, pTab, pSchema) ) continue;
|
||||||
}
|
}
|
||||||
assert( ExprUseYTab(pExpr) );
|
assert( ExprUseYTab(pExpr) );
|
||||||
if( IN_RENAME_OBJECT && pItem->zAlias ){
|
if( IN_RENAME_OBJECT && pItem->zAlias ){
|
||||||
@ -108878,9 +108876,6 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
|
|||||||
** Resolve all names for all expression in an expression list. This is
|
** Resolve all names for all expression in an expression list. This is
|
||||||
** just like sqlite3ResolveExprNames() except that it works for an expression
|
** just like sqlite3ResolveExprNames() except that it works for an expression
|
||||||
** list rather than a single expression.
|
** list rather than a single expression.
|
||||||
**
|
|
||||||
** The return value is SQLITE_OK (0) for success or SQLITE_ERROR (1) for a
|
|
||||||
** failure.
|
|
||||||
*/
|
*/
|
||||||
SQLITE_PRIVATE int sqlite3ResolveExprListNames(
|
SQLITE_PRIVATE int sqlite3ResolveExprListNames(
|
||||||
NameContext *pNC, /* Namespace to resolve expressions in. */
|
NameContext *pNC, /* Namespace to resolve expressions in. */
|
||||||
@ -108889,7 +108884,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames(
|
|||||||
int i;
|
int i;
|
||||||
int savedHasAgg = 0;
|
int savedHasAgg = 0;
|
||||||
Walker w;
|
Walker w;
|
||||||
if( pList==0 ) return SQLITE_OK;
|
if( pList==0 ) return WRC_Continue;
|
||||||
w.pParse = pNC->pParse;
|
w.pParse = pNC->pParse;
|
||||||
w.xExprCallback = resolveExprStep;
|
w.xExprCallback = resolveExprStep;
|
||||||
w.xSelectCallback = resolveSelectStep;
|
w.xSelectCallback = resolveSelectStep;
|
||||||
@ -108903,7 +108898,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames(
|
|||||||
#if SQLITE_MAX_EXPR_DEPTH>0
|
#if SQLITE_MAX_EXPR_DEPTH>0
|
||||||
w.pParse->nHeight += pExpr->nHeight;
|
w.pParse->nHeight += pExpr->nHeight;
|
||||||
if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
|
if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
|
||||||
return SQLITE_ERROR;
|
return WRC_Abort;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sqlite3WalkExprNN(&w, pExpr);
|
sqlite3WalkExprNN(&w, pExpr);
|
||||||
@ -108920,10 +108915,10 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames(
|
|||||||
(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
||||||
pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
||||||
}
|
}
|
||||||
if( w.pParse->nErr>0 ) return SQLITE_ERROR;
|
if( w.pParse->nErr>0 ) return WRC_Abort;
|
||||||
}
|
}
|
||||||
pNC->ncFlags |= savedHasAgg;
|
pNC->ncFlags |= savedHasAgg;
|
||||||
return SQLITE_OK;
|
return WRC_Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -117462,7 +117457,7 @@ static int renameResolveTrigger(Parse *pParse){
|
|||||||
/* ALWAYS() because if the table of the trigger does not exist, the
|
/* ALWAYS() because if the table of the trigger does not exist, the
|
||||||
** error would have been hit before this point */
|
** error would have been hit before this point */
|
||||||
if( ALWAYS(pParse->pTriggerTab) ){
|
if( ALWAYS(pParse->pTriggerTab) ){
|
||||||
rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab)!=0;
|
rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Resolve symbols in WHEN clause */
|
/* Resolve symbols in WHEN clause */
|
||||||
@ -124431,9 +124426,8 @@ create_view_fail:
|
|||||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
|
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
|
||||||
/*
|
/*
|
||||||
** The Table structure pTable is really a VIEW. Fill in the names of
|
** The Table structure pTable is really a VIEW. Fill in the names of
|
||||||
** the columns of the view in the pTable structure. Return non-zero if
|
** the columns of the view in the pTable structure. Return the number
|
||||||
** there are errors. If an error is seen an error message is left
|
** of errors. If an error is seen leave an error message in pParse->zErrMsg.
|
||||||
** in pParse->zErrMsg.
|
|
||||||
*/
|
*/
|
||||||
static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){
|
static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){
|
||||||
Table *pSelTab; /* A fake table from which we get the result set */
|
Table *pSelTab; /* A fake table from which we get the result set */
|
||||||
@ -124556,7 +124550,7 @@ static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){
|
|||||||
sqlite3DeleteColumnNames(db, pTable);
|
sqlite3DeleteColumnNames(db, pTable);
|
||||||
}
|
}
|
||||||
#endif /* SQLITE_OMIT_VIEW */
|
#endif /* SQLITE_OMIT_VIEW */
|
||||||
return nErr + pParse->nErr;
|
return nErr;
|
||||||
}
|
}
|
||||||
SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||||
assert( pTable!=0 );
|
assert( pTable!=0 );
|
||||||
@ -130854,8 +130848,6 @@ static void groupConcatValue(sqlite3_context *context){
|
|||||||
sqlite3_result_error_toobig(context);
|
sqlite3_result_error_toobig(context);
|
||||||
}else if( pAccum->accError==SQLITE_NOMEM ){
|
}else if( pAccum->accError==SQLITE_NOMEM ){
|
||||||
sqlite3_result_error_nomem(context);
|
sqlite3_result_error_nomem(context);
|
||||||
}else if( pGCC->nAccum>0 && pAccum->nChar==0 ){
|
|
||||||
sqlite3_result_text(context, "", 1, SQLITE_STATIC);
|
|
||||||
}else{
|
}else{
|
||||||
const char *zText = sqlite3_str_value(pAccum);
|
const char *zText = sqlite3_str_value(pAccum);
|
||||||
sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT);
|
sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT);
|
||||||
@ -133610,7 +133602,6 @@ SQLITE_PRIVATE Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList
|
|||||||
pRet->pSrc->nSrc = 1;
|
pRet->pSrc->nSrc = 1;
|
||||||
pRet->pPrior = pLeft->pPrior;
|
pRet->pPrior = pLeft->pPrior;
|
||||||
pRet->op = pLeft->op;
|
pRet->op = pLeft->op;
|
||||||
if( pRet->pPrior ) pRet->selFlags |= SF_Values;
|
|
||||||
pLeft->pPrior = 0;
|
pLeft->pPrior = 0;
|
||||||
pLeft->op = TK_SELECT;
|
pLeft->op = TK_SELECT;
|
||||||
assert( pLeft->pNext==0 );
|
assert( pLeft->pNext==0 );
|
||||||
@ -166076,9 +166067,7 @@ static int whereLoopAddBtree(
|
|||||||
" according to whereIsCoveringIndex()\n", pProbe->zName));
|
" according to whereIsCoveringIndex()\n", pProbe->zName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if( m==0
|
}else if( m==0 ){
|
||||||
&& (HasRowid(pTab) || pWInfo->pSelect!=0 || sqlite3FaultSim(700))
|
|
||||||
){
|
|
||||||
WHERETRACE(0x200,
|
WHERETRACE(0x200,
|
||||||
("-> %s a covering index according to bitmasks\n",
|
("-> %s a covering index according to bitmasks\n",
|
||||||
pProbe->zName, m==0 ? "is" : "is not"));
|
pProbe->zName, m==0 ? "is" : "is not"));
|
||||||
@ -167967,10 +167956,6 @@ static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){
|
|||||||
** the right-most table of a subquery that was flattened into the
|
** the right-most table of a subquery that was flattened into the
|
||||||
** main query and that subquery was the right-hand operand of an
|
** main query and that subquery was the right-hand operand of an
|
||||||
** inner join that held an ON or USING clause.
|
** inner join that held an ON or USING clause.
|
||||||
** 6) The ORDER BY clause has 63 or fewer terms
|
|
||||||
** 7) The omit-noop-join optimization is enabled.
|
|
||||||
**
|
|
||||||
** Items (1), (6), and (7) are checked by the caller.
|
|
||||||
**
|
**
|
||||||
** For example, given:
|
** For example, given:
|
||||||
**
|
**
|
||||||
@ -168384,7 +168369,6 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|||||||
if( pOrderBy && pOrderBy->nExpr>=BMS ){
|
if( pOrderBy && pOrderBy->nExpr>=BMS ){
|
||||||
pOrderBy = 0;
|
pOrderBy = 0;
|
||||||
wctrlFlags &= ~WHERE_WANT_DISTINCT;
|
wctrlFlags &= ~WHERE_WANT_DISTINCT;
|
||||||
wctrlFlags |= WHERE_KEEP_ALL_JOINS; /* Disable omit-noop-join opt */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The number of tables in the FROM clause is limited by the number of
|
/* The number of tables in the FROM clause is limited by the number of
|
||||||
@ -168685,10 +168669,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|||||||
** in-line sqlite3WhereCodeOneLoopStart() for performance reasons.
|
** in-line sqlite3WhereCodeOneLoopStart() for performance reasons.
|
||||||
*/
|
*/
|
||||||
notReady = ~(Bitmask)0;
|
notReady = ~(Bitmask)0;
|
||||||
if( pWInfo->nLevel>=2 /* Must be a join, or this opt8n is pointless */
|
if( pWInfo->nLevel>=2
|
||||||
&& pResultSet!=0 /* Condition (1) */
|
&& pResultSet!=0 /* these two combine to guarantee */
|
||||||
&& 0==(wctrlFlags & (WHERE_AGG_DISTINCT|WHERE_KEEP_ALL_JOINS)) /* (1),(6) */
|
&& 0==(wctrlFlags & WHERE_AGG_DISTINCT) /* condition (1) above */
|
||||||
&& OptimizationEnabled(db, SQLITE_OmitNoopJoin) /* (7) */
|
&& OptimizationEnabled(db, SQLITE_OmitNoopJoin)
|
||||||
){
|
){
|
||||||
notReady = whereOmitNoopJoin(pWInfo, notReady);
|
notReady = whereOmitNoopJoin(pWInfo, notReady);
|
||||||
nTabList = pWInfo->nLevel;
|
nTabList = pWInfo->nLevel;
|
||||||
@ -169008,6 +168992,26 @@ whereBeginError:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SQLITE_DEBUG
|
||||||
|
/*
|
||||||
|
** Return true if cursor iCur is opened by instruction k of the
|
||||||
|
** bytecode. Used inside of assert() only.
|
||||||
|
*/
|
||||||
|
static int cursorIsOpen(Vdbe *v, int iCur, int k){
|
||||||
|
while( k>=0 ){
|
||||||
|
VdbeOp *pOp = sqlite3VdbeGetOp(v,k--);
|
||||||
|
if( pOp->p1!=iCur ) continue;
|
||||||
|
if( pOp->opcode==OP_Close ) return 0;
|
||||||
|
if( pOp->opcode==OP_OpenRead ) return 1;
|
||||||
|
if( pOp->opcode==OP_OpenWrite ) return 1;
|
||||||
|
if( pOp->opcode==OP_OpenDup ) return 1;
|
||||||
|
if( pOp->opcode==OP_OpenAutoindex ) return 1;
|
||||||
|
if( pOp->opcode==OP_OpenEphemeral ) return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* SQLITE_DEBUG */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Generate the end of the WHERE loop. See comments on
|
** Generate the end of the WHERE loop. See comments on
|
||||||
** sqlite3WhereBegin() for additional information.
|
** sqlite3WhereBegin() for additional information.
|
||||||
@ -169307,10 +169311,16 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|||||||
** reference. Verify that this is harmless - that the
|
** reference. Verify that this is harmless - that the
|
||||||
** table being referenced really is open.
|
** table being referenced really is open.
|
||||||
*/
|
*/
|
||||||
if( pLoop->wsFlags & WHERE_IDX_ONLY ){
|
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||||
sqlite3ErrorMsg(pParse, "internal query planner error");
|
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
||||||
pParse->rc = SQLITE_INTERNAL;
|
|| cursorIsOpen(v,pOp->p1,k)
|
||||||
}
|
|| pOp->opcode==OP_Offset
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
||||||
|
|| cursorIsOpen(v,pOp->p1,k)
|
||||||
|
);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}else if( pOp->opcode==OP_Rowid ){
|
}else if( pOp->opcode==OP_Rowid ){
|
||||||
pOp->p1 = pLevel->iIdxCur;
|
pOp->p1 = pLevel->iIdxCur;
|
||||||
@ -172581,9 +172591,9 @@ static void updateDeleteLimitError(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( (p->selFlags & (SF_MultiValue|SF_Values))==0
|
if( (p->selFlags & SF_MultiValue)==0 &&
|
||||||
&& (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0
|
(mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 &&
|
||||||
&& cnt>mxSelect
|
cnt>mxSelect
|
||||||
){
|
){
|
||||||
sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
|
sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
|
||||||
}
|
}
|
||||||
@ -236994,11 +237004,7 @@ static int sqlite3Fts5ExprNew(
|
|||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_free(sParse.apPhrase);
|
sqlite3_free(sParse.apPhrase);
|
||||||
if( 0==*pzErr ){
|
*pzErr = sParse.zErr;
|
||||||
*pzErr = sParse.zErr;
|
|
||||||
}else{
|
|
||||||
sqlite3_free(sParse.zErr);
|
|
||||||
}
|
|
||||||
return sParse.rc;
|
return sParse.rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239126,7 +239132,6 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
|
|||||||
assert( pRight->eType==FTS5_STRING
|
assert( pRight->eType==FTS5_STRING
|
||||||
|| pRight->eType==FTS5_TERM
|
|| pRight->eType==FTS5_TERM
|
||||||
|| pRight->eType==FTS5_EOF
|
|| pRight->eType==FTS5_EOF
|
||||||
|| (pRight->eType==FTS5_AND && pParse->bPhraseToAnd)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if( pLeft->eType==FTS5_AND ){
|
if( pLeft->eType==FTS5_AND ){
|
||||||
@ -251294,7 +251299,6 @@ static int fts5UpdateMethod(
|
|||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
}else{
|
}else{
|
||||||
rc = fts5SpecialDelete(pTab, apVal);
|
rc = fts5SpecialDelete(pTab, apVal);
|
||||||
bUpdateOrDelete = 1;
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
|
rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
|
||||||
@ -252469,16 +252473,14 @@ static int sqlite3Fts5GetTokenizer(
|
|||||||
if( pMod==0 ){
|
if( pMod==0 ){
|
||||||
assert( nArg>0 );
|
assert( nArg>0 );
|
||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
if( pzErr ) *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
|
*pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
|
||||||
}else{
|
}else{
|
||||||
rc = pMod->x.xCreate(
|
rc = pMod->x.xCreate(
|
||||||
pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok
|
pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok
|
||||||
);
|
);
|
||||||
pConfig->pTokApi = &pMod->x;
|
pConfig->pTokApi = &pMod->x;
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
if( pzErr && rc!=SQLITE_NOMEM ){
|
if( pzErr ) *pzErr = sqlite3_mprintf("error in tokenizer constructor");
|
||||||
*pzErr = sqlite3_mprintf("error in tokenizer constructor");
|
|
||||||
}
|
|
||||||
}else{
|
}else{
|
||||||
pConfig->ePattern = sqlite3Fts5TokenizerPattern(
|
pConfig->ePattern = sqlite3Fts5TokenizerPattern(
|
||||||
pMod->x.xCreate, pConfig->pTok
|
pMod->x.xCreate, pConfig->pTok
|
||||||
@ -252537,7 +252539,7 @@ static void fts5SourceIdFunc(
|
|||||||
){
|
){
|
||||||
assert( nArg==0 );
|
assert( nArg==0 );
|
||||||
UNUSED_PARAM2(nArg, apUnused);
|
UNUSED_PARAM2(nArg, apUnused);
|
||||||
sqlite3_result_text(pCtx, "fts5: 2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33", -1, SQLITE_TRANSIENT);
|
sqlite3_result_text(pCtx, "fts5: 2024-05-23 13:25:27 96c92aba00c8375bc32fafcdf12429c58bd8aabfcadab6683e35bbb9cdebf19e", -1, SQLITE_TRANSIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -252572,23 +252574,17 @@ static int fts5IntegrityMethod(
|
|||||||
|
|
||||||
assert( pzErr!=0 && *pzErr==0 );
|
assert( pzErr!=0 && *pzErr==0 );
|
||||||
UNUSED_PARAM(isQuick);
|
UNUSED_PARAM(isQuick);
|
||||||
assert( pTab->p.pConfig->pzErrmsg==0 );
|
|
||||||
pTab->p.pConfig->pzErrmsg = pzErr;
|
|
||||||
rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, 0);
|
rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, 0);
|
||||||
if( *pzErr==0 && rc!=SQLITE_OK ){
|
if( (rc&0xff)==SQLITE_CORRUPT ){
|
||||||
if( (rc&0xff)==SQLITE_CORRUPT ){
|
*pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
|
||||||
*pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
|
zSchema, zTabname);
|
||||||
zSchema, zTabname);
|
rc = (*pzErr) ? SQLITE_OK : SQLITE_NOMEM;
|
||||||
rc = (*pzErr) ? SQLITE_OK : SQLITE_NOMEM;
|
}else if( rc!=SQLITE_OK ){
|
||||||
}else{
|
*pzErr = sqlite3_mprintf("unable to validate the inverted index for"
|
||||||
*pzErr = sqlite3_mprintf("unable to validate the inverted index for"
|
" FTS5 table %s.%s: %s",
|
||||||
" FTS5 table %s.%s: %s",
|
zSchema, zTabname, sqlite3_errstr(rc));
|
||||||
zSchema, zTabname, sqlite3_errstr(rc));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
|
sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
|
||||||
pTab->p.pConfig->pzErrmsg = 0;
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -254022,7 +254018,7 @@ static int fts5AsciiCreate(
|
|||||||
int i;
|
int i;
|
||||||
memset(p, 0, sizeof(AsciiTokenizer));
|
memset(p, 0, sizeof(AsciiTokenizer));
|
||||||
memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
|
memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
|
||||||
for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
|
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
|
||||||
const char *zArg = azArg[i+1];
|
const char *zArg = azArg[i+1];
|
||||||
if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
|
if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){
|
||||||
fts5AsciiAddExceptions(p, zArg, 1);
|
fts5AsciiAddExceptions(p, zArg, 1);
|
||||||
@ -254033,7 +254029,6 @@ static int fts5AsciiCreate(
|
|||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( rc==SQLITE_OK && i<nArg ) rc = SQLITE_ERROR;
|
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
fts5AsciiDelete((Fts5Tokenizer*)p);
|
fts5AsciiDelete((Fts5Tokenizer*)p);
|
||||||
p = 0;
|
p = 0;
|
||||||
@ -254325,16 +254320,17 @@ static int fts5UnicodeCreate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Search for a "categories" argument */
|
/* Search for a "categories" argument */
|
||||||
for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
|
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
|
||||||
if( 0==sqlite3_stricmp(azArg[i], "categories") ){
|
if( 0==sqlite3_stricmp(azArg[i], "categories") ){
|
||||||
zCat = azArg[i+1];
|
zCat = azArg[i+1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = unicodeSetCategories(p, zCat);
|
rc = unicodeSetCategories(p, zCat);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
|
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
|
||||||
const char *zArg = azArg[i+1];
|
const char *zArg = azArg[i+1];
|
||||||
if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
|
if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
|
||||||
if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
|
if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
|
||||||
@ -254359,7 +254355,6 @@ static int fts5UnicodeCreate(
|
|||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;
|
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
rc = SQLITE_NOMEM;
|
rc = SQLITE_NOMEM;
|
||||||
@ -255242,7 +255237,7 @@ static int fts5TriCreate(
|
|||||||
int i;
|
int i;
|
||||||
pNew->bFold = 1;
|
pNew->bFold = 1;
|
||||||
pNew->iFoldParam = 0;
|
pNew->iFoldParam = 0;
|
||||||
for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){
|
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
|
||||||
const char *zArg = azArg[i+1];
|
const char *zArg = azArg[i+1];
|
||||||
if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
|
if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
|
||||||
if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
|
if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
|
||||||
@ -255260,7 +255255,6 @@ static int fts5TriCreate(
|
|||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR;
|
|
||||||
|
|
||||||
if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
|
if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
|
||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
|
6
deps/sqlite/sqlite3.h
vendored
6
deps/sqlite/sqlite3.h
vendored
@ -146,9 +146,9 @@ extern "C" {
|
|||||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||||
** [sqlite_version()] and [sqlite_source_id()].
|
** [sqlite_version()] and [sqlite_source_id()].
|
||||||
*/
|
*/
|
||||||
#define SQLITE_VERSION "3.46.1"
|
#define SQLITE_VERSION "3.46.0"
|
||||||
#define SQLITE_VERSION_NUMBER 3046001
|
#define SQLITE_VERSION_NUMBER 3046000
|
||||||
#define SQLITE_SOURCE_ID "2024-08-13 09:16:08 c9c2ab54ba1f5f46360f1b4f35d849cd3f080e6fc2b6c60e91b16c63f69a1e33"
|
#define SQLITE_SOURCE_ID "2024-05-23 13:25:27 96c92aba00c8375bc32fafcdf12429c58bd8aabfcadab6683e35bbb9cdebf19e"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Run-Time Library Version Numbers
|
** CAPI3REF: Run-Time Library Version Numbers
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
package="com.unprompted.tildefriends"
|
package="com.unprompted.tildefriends"
|
||||||
android:versionCode="26"
|
android:versionCode="26"
|
||||||
android:versionName="0.0.22-wip">
|
android:versionName="0.0.22-wip">
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<application
|
<application
|
||||||
android:label="Tilde Friends"
|
android:label="Tilde Friends"
|
||||||
|
@ -7,7 +7,6 @@ import android.content.ComponentName;
|
|||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
@ -16,7 +15,6 @@ import android.os.Parcel;
|
|||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
import android.text.InputType;
|
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
@ -34,7 +32,6 @@ import android.webkit.WebChromeClient;
|
|||||||
import android.webkit.WebResourceRequest;
|
import android.webkit.WebResourceRequest;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@ -69,7 +66,7 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
Log.w("tildefriends", "system.loadLibrary() completed.");
|
Log.w("tildefriends", "system.loadLibrary() completed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static native int tf_server_main(String files_dir, String apk_path, String out_port_file_path, ConnectivityManager connectivity_manager);
|
public static native int tf_server_main(String files_dir, String apk_path, String out_port_file_path);
|
||||||
public static native int tf_sandbox_main(int pipe_fd);
|
public static native int tf_sandbox_main(int pipe_fd);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -151,11 +148,7 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Log.w("tildefriends", "Calling tf_server_main.");
|
Log.w("tildefriends", "Calling tf_server_main.");
|
||||||
int result = tf_server_main(
|
int result = tf_server_main(getFilesDir().toString(), getPackageResourcePath().toString(), port_file_path);
|
||||||
getFilesDir().toString(),
|
|
||||||
getPackageResourcePath().toString(),
|
|
||||||
port_file_path,
|
|
||||||
(ConnectivityManager)getApplicationContext().getSystemService(CONNECTIVITY_SERVICE));
|
|
||||||
Log.w("tildefriends", "tf_server_main returned " + result + ".");
|
Log.w("tildefriends", "tf_server_main returned " + result + ".");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -198,6 +191,30 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
});
|
});
|
||||||
|
|
||||||
web_view.setWebChromeClient(new WebChromeClient() {
|
web_view.setWebChromeClient(new WebChromeClient() {
|
||||||
|
@Override
|
||||||
|
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
|
||||||
|
new AlertDialog.Builder(view.getContext())
|
||||||
|
.setTitle("Tilde Friends")
|
||||||
|
.setMessage(message)
|
||||||
|
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
result.confirm();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick(DialogInterface dialog, int which)
|
||||||
|
{
|
||||||
|
result.cancel();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
|
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
|
||||||
new AlertDialog.Builder(view.getContext())
|
new AlertDialog.Builder(view.getContext())
|
||||||
@ -215,59 +232,6 @@ public class TildeFriendsActivity extends Activity {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
|
|
||||||
new AlertDialog.Builder(view.getContext())
|
|
||||||
.setTitle("Tilde Friends")
|
|
||||||
.setMessage(message)
|
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
|
||||||
{
|
|
||||||
public void onClick(DialogInterface dialog, int which)
|
|
||||||
{
|
|
||||||
result.confirm();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
|
|
||||||
{
|
|
||||||
public void onClick(DialogInterface dialog, int which)
|
|
||||||
{
|
|
||||||
result.cancel();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.create()
|
|
||||||
.show();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
|
|
||||||
EditText input = new EditText(view.getContext());
|
|
||||||
input.setInputType(InputType.TYPE_CLASS_TEXT);
|
|
||||||
input.setText(defaultValue);
|
|
||||||
|
|
||||||
new AlertDialog.Builder(view.getContext())
|
|
||||||
.setTitle("Tilde Friends")
|
|
||||||
.setMessage(message)
|
|
||||||
.setView(input)
|
|
||||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener()
|
|
||||||
{
|
|
||||||
public void onClick(DialogInterface dialog, int which)
|
|
||||||
{
|
|
||||||
result.confirm(input.getText().toString());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener()
|
|
||||||
{
|
|
||||||
public void onClick(DialogInterface dialog, int which)
|
|
||||||
{
|
|
||||||
result.cancel();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.create()
|
|
||||||
.show();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** https://stackoverflow.com/questions/5907369/file-upload-in-webview
|
** https://stackoverflow.com/questions/5907369/file-upload-in-webview
|
||||||
** https://stackoverflow.com/questions/8586691/how-to-open-file-save-dialog-in-android
|
** https://stackoverflow.com/questions/8586691/how-to-open-file-save-dialog-in-android
|
||||||
|
@ -1071,7 +1071,7 @@ void* tf_http_get_user_data(tf_http_t* http)
|
|||||||
|
|
||||||
const char* tf_http_get_cookie(const char* cookie_header, const char* name)
|
const char* tf_http_get_cookie(const char* cookie_header, const char* name)
|
||||||
{
|
{
|
||||||
if (!cookie_header || !name)
|
if (!cookie_header)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1484,39 +1484,27 @@ static void _httpd_endpoint_login_work(tf_ssb_t* ssb, void* user_data)
|
|||||||
|
|
||||||
if (form_register && strcmp(form_register, "1") == 0)
|
if (form_register && strcmp(form_register, "1") == 0)
|
||||||
{
|
{
|
||||||
bool registered = false;
|
if (!have_account && _is_name_valid(account_name) && password && confirm && strcmp(password, confirm) == 0 &&
|
||||||
if (!have_account && _is_name_valid(account_name) && password && confirm && strcmp(password, confirm) == 0)
|
tf_ssb_db_register_account(ssb, account_name, password))
|
||||||
{
|
{
|
||||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
tf_free((void*)send_session);
|
||||||
registered = tf_ssb_db_register_account(tf_ssb_get_loop(ssb), db, context, account_name, password);
|
send_session = _make_session_jwt(ssb, account_name);
|
||||||
tf_ssb_release_db_writer(ssb, db);
|
may_become_first_admin = true;
|
||||||
if (registered)
|
|
||||||
{
|
|
||||||
tf_free((void*)send_session);
|
|
||||||
send_session = _make_session_jwt(ssb, account_name);
|
|
||||||
may_become_first_admin = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!registered)
|
else
|
||||||
{
|
{
|
||||||
login_error = "Error registering account.";
|
login_error = "Error registering account.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (change && strcmp(change, "1") == 0)
|
else if (change && strcmp(change, "1") == 0)
|
||||||
{
|
{
|
||||||
bool set = false;
|
if (have_account && _is_name_valid(account_name) && new_password && confirm && strcmp(new_password, confirm) == 0 && _verify_password(password, account_passwd) &&
|
||||||
if (have_account && _is_name_valid(account_name) && new_password && confirm && strcmp(new_password, confirm) == 0 && _verify_password(password, account_passwd))
|
tf_ssb_db_set_account_password(ssb, account_name, new_password))
|
||||||
{
|
{
|
||||||
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
tf_free((void*)send_session);
|
||||||
set = tf_ssb_db_set_account_password(tf_ssb_get_loop(ssb), db, context, account_name, new_password);
|
send_session = _make_session_jwt(ssb, account_name);
|
||||||
tf_ssb_release_db_writer(ssb, db);
|
|
||||||
if (set)
|
|
||||||
{
|
|
||||||
tf_free((void*)send_session);
|
|
||||||
send_session = _make_session_jwt(ssb, account_name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!set)
|
else
|
||||||
{
|
{
|
||||||
login_error = "Error changing password.";
|
login_error = "Error changing password.";
|
||||||
}
|
}
|
||||||
|
13
src/main.c
13
src/main.c
@ -9,7 +9,6 @@
|
|||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "util.js.h"
|
#include "util.js.h"
|
||||||
|
|
||||||
#include "ares.h"
|
|
||||||
#include "backtrace.h"
|
#include "backtrace.h"
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
#include "unzip.h"
|
#include "unzip.h"
|
||||||
@ -751,7 +750,7 @@ static void _tf_service_stop()
|
|||||||
(*s_jni_env)->CallStaticVoidMethod(s_jni_env, c, stop_sandbox);
|
(*s_jni_env)->CallStaticVoidMethod(s_jni_env, c, stop_sandbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
static jint _tf_server_main(JNIEnv* env, jobject this_object, jstring files_dir, jstring apk_path, jstring out_port_file_path, jobject connectivity_manager)
|
static jint _tf_server_main(JNIEnv* env, jobject this_object, jstring files_dir, jstring apk_path, jstring out_port_file_path)
|
||||||
{
|
{
|
||||||
s_jni_env = env;
|
s_jni_env = env;
|
||||||
|
|
||||||
@ -759,9 +758,6 @@ static jint _tf_server_main(JNIEnv* env, jobject this_object, jstring files_dir,
|
|||||||
_startup(0, (char*[]) { NULL });
|
_startup(0, (char*[]) { NULL });
|
||||||
tf_printf("That was startup.\n");
|
tf_printf("That was startup.\n");
|
||||||
|
|
||||||
ares_library_init_android(connectivity_manager);
|
|
||||||
ares_library_init(0);
|
|
||||||
|
|
||||||
const char* files = (*env)->GetStringUTFChars(env, files_dir, NULL);
|
const char* files = (*env)->GetStringUTFChars(env, files_dir, NULL);
|
||||||
const char* apk = (*env)->GetStringUTFChars(env, apk_path, NULL);
|
const char* apk = (*env)->GetStringUTFChars(env, apk_path, NULL);
|
||||||
const char* out_port_file = (*env)->GetStringUTFChars(env, out_port_file_path, NULL);
|
const char* out_port_file = (*env)->GetStringUTFChars(env, out_port_file_path, NULL);
|
||||||
@ -798,7 +794,6 @@ static jint _tf_server_main(JNIEnv* env, jobject this_object, jstring files_dir,
|
|||||||
(*env)->ReleaseStringUTFChars(env, apk_path, apk);
|
(*env)->ReleaseStringUTFChars(env, apk_path, apk);
|
||||||
(*env)->ReleaseStringUTFChars(env, out_port_file_path, out_port_file);
|
(*env)->ReleaseStringUTFChars(env, out_port_file_path, out_port_file);
|
||||||
|
|
||||||
ares_library_cleanup();
|
|
||||||
tf_mem_shutdown();
|
tf_mem_shutdown();
|
||||||
tf_printf("tf_server_main finished with %d.", result);
|
tf_printf("tf_server_main finished with %d.", result);
|
||||||
|
|
||||||
@ -851,7 +846,7 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
|||||||
|
|
||||||
tf_printf("Registering method.\n");
|
tf_printf("Registering method.\n");
|
||||||
static const JNINativeMethod methods[] = {
|
static const JNINativeMethod methods[] = {
|
||||||
{ "tf_server_main", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/net/ConnectivityManager;)I", _tf_server_main },
|
{ "tf_server_main", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", _tf_server_main },
|
||||||
{ "tf_sandbox_main", "(I)I", _tf_sandbox_main },
|
{ "tf_sandbox_main", "(I)I", _tf_sandbox_main },
|
||||||
};
|
};
|
||||||
int result = (*env)->RegisterNatives(env, c, methods, (int)_countof(methods));
|
int result = (*env)->RegisterNatives(env, c, methods, (int)_countof(methods));
|
||||||
@ -860,8 +855,6 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ares_library_init_jvm(vm);
|
|
||||||
|
|
||||||
tf_printf("Done.\n");
|
tf_printf("Done.\n");
|
||||||
return JNI_VERSION_1_6;
|
return JNI_VERSION_1_6;
|
||||||
}
|
}
|
||||||
@ -896,7 +889,6 @@ void tf_run_thread_start(const char* zip_path)
|
|||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
_startup(argc, argv);
|
_startup(argc, argv);
|
||||||
ares_library_init(0);
|
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if (argc >= 2)
|
if (argc >= 2)
|
||||||
@ -917,7 +909,6 @@ int main(int argc, char* argv[])
|
|||||||
result = _tf_command_run(argv[0], argc, argv);
|
result = _tf_command_run(argv[0], argc, argv);
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
ares_library_cleanup();
|
|
||||||
tf_mem_shutdown();
|
tf_mem_shutdown();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
80
src/ssb.c
80
src/ssb.c
@ -77,9 +77,6 @@ enum
|
|||||||
k_tf_ssb_rpc_message_body_length_max = 1 * 1024 * 1024,
|
k_tf_ssb_rpc_message_body_length_max = 1 * 1024 * 1024,
|
||||||
k_debug_close_message_count = 256,
|
k_debug_close_message_count = 256,
|
||||||
k_debug_close_connection_count = 32,
|
k_debug_close_connection_count = 32,
|
||||||
k_seed_expire_seconds = 10 * 60,
|
|
||||||
k_seed_check_interval_seconds = 5 * 60,
|
|
||||||
k_udp_discovery_expires_seconds = 10,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _tf_ssb_broadcast_t tf_ssb_broadcast_t;
|
typedef struct _tf_ssb_broadcast_t tf_ssb_broadcast_t;
|
||||||
@ -119,9 +116,7 @@ typedef struct _tf_ssb_broadcast_t
|
|||||||
tf_ssb_broadcast_t* next;
|
tf_ssb_broadcast_t* next;
|
||||||
time_t ctime;
|
time_t ctime;
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
time_t expires_at;
|
|
||||||
char host[256];
|
char host[256];
|
||||||
tf_ssb_broadcast_origin_t origin;
|
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
tf_ssb_connection_t* tunnel_connection;
|
tf_ssb_connection_t* tunnel_connection;
|
||||||
uint8_t pub[crypto_sign_PUBLICKEYBYTES];
|
uint8_t pub[crypto_sign_PUBLICKEYBYTES];
|
||||||
@ -265,11 +260,8 @@ typedef struct _tf_ssb_t
|
|||||||
|
|
||||||
uv_thread_t thread_self;
|
uv_thread_t thread_self;
|
||||||
bool is_room;
|
bool is_room;
|
||||||
bool is_replicator;
|
|
||||||
bool is_peer_exchange;
|
|
||||||
char* room_name;
|
char* room_name;
|
||||||
char seeds_host[256];
|
char seeds_host[256];
|
||||||
time_t last_seed_check;
|
|
||||||
|
|
||||||
tf_ssb_timer_t** timers;
|
tf_ssb_timer_t** timers;
|
||||||
int timers_count;
|
int timers_count;
|
||||||
@ -365,7 +357,7 @@ static JSClassID _connection_class_id;
|
|||||||
static int s_connection_index;
|
static int s_connection_index;
|
||||||
static int s_tunnel_index;
|
static int s_tunnel_index;
|
||||||
|
|
||||||
static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broadcast, int expires_seconds);
|
static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broadcast);
|
||||||
static void _tf_ssb_connection_client_send_hello(tf_ssb_connection_t* connection);
|
static void _tf_ssb_connection_client_send_hello(tf_ssb_connection_t* connection);
|
||||||
static void _tf_ssb_connection_close(tf_ssb_connection_t* connection, const char* reason);
|
static void _tf_ssb_connection_close(tf_ssb_connection_t* connection, const char* reason);
|
||||||
static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const char* reason);
|
static void _tf_ssb_connection_destroy(tf_ssb_connection_t* connection, const char* reason);
|
||||||
@ -2198,7 +2190,6 @@ tf_ssb_t* tf_ssb_create(uv_loop_t* loop, JSContext* context, const char* db_path
|
|||||||
{
|
{
|
||||||
tf_ssb_t* ssb = tf_malloc(sizeof(tf_ssb_t));
|
tf_ssb_t* ssb = tf_malloc(sizeof(tf_ssb_t));
|
||||||
memset(ssb, 0, sizeof(*ssb));
|
memset(ssb, 0, sizeof(*ssb));
|
||||||
ssb->is_replicator = true;
|
|
||||||
|
|
||||||
const char* actual_key = network_key ? network_key : k_ssb_network_string;
|
const char* actual_key = network_key ? network_key : k_ssb_network_string;
|
||||||
if (sodium_hex2bin(ssb->network_key, sizeof(ssb->network_key), actual_key, strlen(actual_key), ": ", NULL, NULL))
|
if (sodium_hex2bin(ssb->network_key, sizeof(ssb->network_key), actual_key, strlen(actual_key), ": ", NULL, NULL))
|
||||||
@ -2952,10 +2943,10 @@ static void _tf_ssb_update_seeds_after_work(tf_ssb_t* ssb, int status, void* use
|
|||||||
seeds_t* seeds = user_data;
|
seeds_t* seeds = user_data;
|
||||||
for (int i = 0; i < seeds->seeds_count; i++)
|
for (int i = 0; i < seeds->seeds_count; i++)
|
||||||
{
|
{
|
||||||
tf_ssb_broadcast_t broadcast = { .origin = k_tf_ssb_broadcast_origin_peer_exchange };
|
tf_ssb_broadcast_t broadcast = { 0 };
|
||||||
if (_tf_ssb_parse_broadcast(seeds->seeds[i], &broadcast))
|
if (_tf_ssb_parse_broadcast(seeds->seeds[i], &broadcast))
|
||||||
{
|
{
|
||||||
_tf_ssb_add_broadcast(ssb, &broadcast, k_seed_expire_seconds);
|
_tf_ssb_add_broadcast(ssb, &broadcast);
|
||||||
}
|
}
|
||||||
tf_free(seeds->seeds[i]);
|
tf_free(seeds->seeds[i]);
|
||||||
}
|
}
|
||||||
@ -2980,12 +2971,11 @@ static void _tf_ssb_broadcast_timer(uv_timer_t* timer)
|
|||||||
uv_free_interface_addresses(info, count);
|
uv_free_interface_addresses(info, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t now = time(NULL);
|
seeds_t* seeds = tf_malloc(sizeof(seeds_t));
|
||||||
if (ssb->is_peer_exchange && *ssb->seeds_host && now - ssb->last_seed_check > k_seed_check_interval_seconds)
|
*seeds = (seeds_t) { 0 };
|
||||||
|
|
||||||
|
if (*ssb->seeds_host)
|
||||||
{
|
{
|
||||||
seeds_t* seeds = tf_malloc(sizeof(seeds_t));
|
|
||||||
*seeds = (seeds_t) { 0 };
|
|
||||||
ssb->last_seed_check = now;
|
|
||||||
tf_ssb_run_work(ssb, _tf_ssb_update_seeds_work, _tf_ssb_update_seeds_after_work, seeds);
|
tf_ssb_run_work(ssb, _tf_ssb_update_seeds_work, _tf_ssb_update_seeds_after_work, seeds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3100,7 +3090,7 @@ static void _tf_ssb_notify_broadcasts_changed(tf_ssb_t* ssb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broadcast, int expires_seconds)
|
static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broadcast)
|
||||||
{
|
{
|
||||||
if (memcmp(broadcast->pub, ssb->pub, sizeof(ssb->pub)) == 0)
|
if (memcmp(broadcast->pub, ssb->pub, sizeof(ssb->pub)) == 0)
|
||||||
{
|
{
|
||||||
@ -3114,7 +3104,6 @@ static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broad
|
|||||||
if (node->tunnel_connection == broadcast->tunnel_connection && memcmp(node->pub, broadcast->pub, sizeof(node->pub)) == 0)
|
if (node->tunnel_connection == broadcast->tunnel_connection && memcmp(node->pub, broadcast->pub, sizeof(node->pub)) == 0)
|
||||||
{
|
{
|
||||||
node->mtime = time(NULL);
|
node->mtime = time(NULL);
|
||||||
node->expires_at = node->mtime + expires_seconds;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3127,7 +3116,6 @@ static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broad
|
|||||||
node->addr.sin_addr.s_addr == broadcast->addr.sin_addr.s_addr && memcmp(node->pub, broadcast->pub, sizeof(node->pub)) == 0)
|
node->addr.sin_addr.s_addr == broadcast->addr.sin_addr.s_addr && memcmp(node->pub, broadcast->pub, sizeof(node->pub)) == 0)
|
||||||
{
|
{
|
||||||
node->mtime = time(NULL);
|
node->mtime = time(NULL);
|
||||||
node->expires_at = node->mtime + expires_seconds;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3144,22 +3132,12 @@ static void _tf_ssb_add_broadcast(tf_ssb_t* ssb, const tf_ssb_broadcast_t* broad
|
|||||||
node->next = ssb->broadcasts;
|
node->next = ssb->broadcasts;
|
||||||
node->ctime = time(NULL);
|
node->ctime = time(NULL);
|
||||||
node->mtime = node->ctime;
|
node->mtime = node->ctime;
|
||||||
node->expires_at = node->mtime + expires_seconds;
|
|
||||||
ssb->broadcasts = node;
|
ssb->broadcasts = node;
|
||||||
ssb->broadcasts_count++;
|
ssb->broadcasts_count++;
|
||||||
|
|
||||||
_tf_ssb_notify_broadcasts_changed(ssb);
|
_tf_ssb_notify_broadcasts_changed(ssb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_add_broadcast(tf_ssb_t* ssb, const char* connection, tf_ssb_broadcast_origin_t origin, int64_t expires_seconds)
|
|
||||||
{
|
|
||||||
tf_ssb_broadcast_t broadcast = { .origin = origin };
|
|
||||||
if (_tf_ssb_parse_broadcast(connection, &broadcast))
|
|
||||||
{
|
|
||||||
_tf_ssb_add_broadcast(ssb, &broadcast, expires_seconds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _tf_ssb_on_broadcast_listener_recv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)
|
static void _tf_ssb_on_broadcast_listener_recv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags)
|
||||||
{
|
{
|
||||||
if (nread <= 0)
|
if (nread <= 0)
|
||||||
@ -3176,19 +3154,18 @@ static void _tf_ssb_on_broadcast_listener_recv(uv_udp_t* handle, ssize_t nread,
|
|||||||
char* entry = strtok_r(buf->base, k_delim, &state);
|
char* entry = strtok_r(buf->base, k_delim, &state);
|
||||||
while (entry)
|
while (entry)
|
||||||
{
|
{
|
||||||
tf_ssb_broadcast_t broadcast = { .origin = k_tf_ssb_broadcast_origin_discovery };
|
tf_ssb_broadcast_t broadcast = { 0 };
|
||||||
if (_tf_ssb_parse_broadcast(entry, &broadcast))
|
if (_tf_ssb_parse_broadcast(entry, &broadcast))
|
||||||
{
|
{
|
||||||
_tf_ssb_add_broadcast(ssb, &broadcast, k_udp_discovery_expires_seconds);
|
_tf_ssb_add_broadcast(ssb, &broadcast);
|
||||||
}
|
}
|
||||||
entry = strtok_r(NULL, k_delim, &state);
|
entry = strtok_r(NULL, k_delim, &state);
|
||||||
}
|
}
|
||||||
tf_free(buf->base);
|
tf_free(buf->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_visit_broadcasts(tf_ssb_t* ssb,
|
void tf_ssb_visit_broadcasts(
|
||||||
void (*callback)(const char* host, const struct sockaddr_in* addr, tf_ssb_broadcast_origin_t origin, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data),
|
tf_ssb_t* ssb, void (*callback)(const char* host, const struct sockaddr_in* addr, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data), void* user_data)
|
||||||
void* user_data)
|
|
||||||
{
|
{
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
tf_ssb_broadcast_t* next = NULL;
|
tf_ssb_broadcast_t* next = NULL;
|
||||||
@ -3198,7 +3175,7 @@ void tf_ssb_visit_broadcasts(tf_ssb_t* ssb,
|
|||||||
if (node->mtime - now < 60)
|
if (node->mtime - now < 60)
|
||||||
{
|
{
|
||||||
tf_trace_begin(ssb->trace, "broadcast");
|
tf_trace_begin(ssb->trace, "broadcast");
|
||||||
callback(node->host, &node->addr, node->origin, node->tunnel_connection, node->pub, user_data);
|
callback(node->host, &node->addr, node->tunnel_connection, node->pub, user_data);
|
||||||
tf_trace_end(ssb->trace);
|
tf_trace_end(ssb->trace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3211,7 +3188,7 @@ static void _tf_ssb_broadcast_cleanup_timer(uv_timer_t* timer)
|
|||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
for (tf_ssb_broadcast_t** it = &ssb->broadcasts; *it;)
|
for (tf_ssb_broadcast_t** it = &ssb->broadcasts; *it;)
|
||||||
{
|
{
|
||||||
if (!(*it)->tunnel_connection && now > (*it)->expires_at)
|
if (!(*it)->tunnel_connection && (*it)->mtime < now - 10)
|
||||||
{
|
{
|
||||||
tf_ssb_broadcast_t* node = *it;
|
tf_ssb_broadcast_t* node = *it;
|
||||||
*it = node->next;
|
*it = node->next;
|
||||||
@ -3624,11 +3601,10 @@ void tf_ssb_notify_blob_want_added(tf_ssb_t* ssb, const char* id)
|
|||||||
void tf_ssb_connection_add_room_attendant(tf_ssb_connection_t* connection, const char* id)
|
void tf_ssb_connection_add_room_attendant(tf_ssb_connection_t* connection, const char* id)
|
||||||
{
|
{
|
||||||
tf_ssb_broadcast_t broadcast = {
|
tf_ssb_broadcast_t broadcast = {
|
||||||
.origin = k_tf_ssb_broadcast_origin_room,
|
|
||||||
.tunnel_connection = connection,
|
.tunnel_connection = connection,
|
||||||
};
|
};
|
||||||
tf_ssb_id_str_to_bin(broadcast.pub, id);
|
tf_ssb_id_str_to_bin(broadcast.pub, id);
|
||||||
_tf_ssb_add_broadcast(connection->ssb, &broadcast, 0);
|
_tf_ssb_add_broadcast(connection->ssb, &broadcast);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_ssb_connection_remove_room_attendant(tf_ssb_connection_t* connection, const char* id)
|
void tf_ssb_connection_remove_room_attendant(tf_ssb_connection_t* connection, const char* id)
|
||||||
@ -4009,26 +3985,6 @@ const char* tf_ssb_get_room_name(tf_ssb_t* ssb)
|
|||||||
return ssb->room_name;
|
return ssb->room_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tf_ssb_is_replicator(tf_ssb_t* ssb)
|
|
||||||
{
|
|
||||||
return ssb->is_replicator;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tf_ssb_set_is_replicator(tf_ssb_t* ssb, bool is_replicator)
|
|
||||||
{
|
|
||||||
ssb->is_replicator = is_replicator;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tf_ssb_is_peer_exchange(tf_ssb_t* ssb)
|
|
||||||
{
|
|
||||||
return ssb->is_peer_exchange;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tf_ssb_set_is_peer_exchange(tf_ssb_t* ssb, bool is_peer_exchange)
|
|
||||||
{
|
|
||||||
ssb->is_peer_exchange = is_peer_exchange;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tf_ssb_set_room_name(tf_ssb_t* ssb, const char* room_name)
|
void tf_ssb_set_room_name(tf_ssb_t* ssb, const char* room_name)
|
||||||
{
|
{
|
||||||
tf_free(ssb->room_name);
|
tf_free(ssb->room_name);
|
||||||
@ -4038,8 +3994,6 @@ void tf_ssb_set_room_name(tf_ssb_t* ssb, const char* room_name)
|
|||||||
typedef struct _update_settings_t
|
typedef struct _update_settings_t
|
||||||
{
|
{
|
||||||
bool is_room;
|
bool is_room;
|
||||||
bool is_replicator;
|
|
||||||
bool is_peer_exchange;
|
|
||||||
char seeds_host[256];
|
char seeds_host[256];
|
||||||
char room_name[1024];
|
char room_name[1024];
|
||||||
} update_settings_t;
|
} update_settings_t;
|
||||||
@ -4097,8 +4051,6 @@ static void _tf_ssb_update_settings_work(tf_ssb_t* ssb, void* user_data)
|
|||||||
{
|
{
|
||||||
update_settings_t* update = user_data;
|
update_settings_t* update = user_data;
|
||||||
update->is_room = _get_global_setting_bool(ssb, "room", true);
|
update->is_room = _get_global_setting_bool(ssb, "room", true);
|
||||||
update->is_replicator = _get_global_setting_bool(ssb, "replicator", true);
|
|
||||||
update->is_peer_exchange = _get_global_setting_bool(ssb, "peer_exchange", true);
|
|
||||||
_get_global_setting_string(ssb, "room_name", update->room_name, sizeof(update->room_name));
|
_get_global_setting_string(ssb, "room_name", update->room_name, sizeof(update->room_name));
|
||||||
_get_global_setting_string(ssb, "seeds_host", update->seeds_host, sizeof(update->seeds_host));
|
_get_global_setting_string(ssb, "seeds_host", update->seeds_host, sizeof(update->seeds_host));
|
||||||
}
|
}
|
||||||
@ -4108,8 +4060,6 @@ static void _tf_ssb_update_settings_after_work(tf_ssb_t* ssb, int result, void*
|
|||||||
update_settings_t* update = user_data;
|
update_settings_t* update = user_data;
|
||||||
tf_ssb_set_is_room(ssb, update->is_room);
|
tf_ssb_set_is_room(ssb, update->is_room);
|
||||||
tf_ssb_set_room_name(ssb, update->room_name);
|
tf_ssb_set_room_name(ssb, update->room_name);
|
||||||
tf_ssb_set_is_peer_exchange(ssb, update->is_peer_exchange);
|
|
||||||
tf_ssb_set_is_replicator(ssb, update->is_replicator);
|
|
||||||
snprintf(ssb->seeds_host, sizeof(ssb->seeds_host), "%s", update->seeds_host);
|
snprintf(ssb->seeds_host, sizeof(ssb->seeds_host), "%s", update->seeds_host);
|
||||||
_tf_ssb_start_update_settings(ssb);
|
_tf_ssb_start_update_settings(ssb);
|
||||||
tf_free(update);
|
tf_free(update);
|
||||||
|
84
src/ssb.db.c
84
src/ssb.db.c
@ -1644,13 +1644,14 @@ bool tf_ssb_db_get_account_password_hash(tf_ssb_t* ssb, const char* name, char*
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tf_ssb_db_set_account_password(uv_loop_t* loop, sqlite3* db, JSContext* context, const char* name, const char* password)
|
bool tf_ssb_db_set_account_password(tf_ssb_t* ssb, const char* name, const char* password)
|
||||||
{
|
{
|
||||||
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
bool result = false;
|
bool result = false;
|
||||||
static const int k_salt_length = 12;
|
static const int k_salt_length = 12;
|
||||||
|
|
||||||
char buffer[16];
|
char buffer[16];
|
||||||
size_t bytes = uv_random(loop, &(uv_random_t) { 0 }, buffer, sizeof(buffer), 0, NULL) == 0 ? sizeof(buffer) : 0;
|
size_t bytes = uv_random(tf_ssb_get_loop(ssb), &(uv_random_t) { 0 }, buffer, sizeof(buffer), 0, NULL) == 0 ? sizeof(buffer) : 0;
|
||||||
char output[7 + 22 + 1];
|
char output[7 + 22 + 1];
|
||||||
char* salt = crypt_gensalt_rn("$2b$", k_salt_length, buffer, bytes, output, sizeof(output));
|
char* salt = crypt_gensalt_rn("$2b$", k_salt_length, buffer, bytes, output, sizeof(output));
|
||||||
char hash_output[7 + 22 + 31 + 1];
|
char hash_output[7 + 22 + 31 + 1];
|
||||||
@ -1662,6 +1663,7 @@ bool tf_ssb_db_set_account_password(uv_loop_t* loop, sqlite3* db, JSContext* con
|
|||||||
size_t user_length = 0;
|
size_t user_length = 0;
|
||||||
const char* user_string = JS_ToCStringLen(context, &user_length, user_json);
|
const char* user_string = JS_ToCStringLen(context, &user_length, user_json);
|
||||||
|
|
||||||
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
sqlite3_stmt* statement = NULL;
|
sqlite3_stmt* statement = NULL;
|
||||||
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ('auth', 'user:' || ?, ?)", -1, &statement, NULL) == SQLITE_OK)
|
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ('auth', 'user:' || ?, ?)", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
@ -1671,6 +1673,7 @@ bool tf_ssb_db_set_account_password(uv_loop_t* loop, sqlite3* db, JSContext* con
|
|||||||
}
|
}
|
||||||
sqlite3_finalize(statement);
|
sqlite3_finalize(statement);
|
||||||
}
|
}
|
||||||
|
tf_ssb_release_db_writer(ssb, db);
|
||||||
|
|
||||||
JS_FreeCString(context, user_string);
|
JS_FreeCString(context, user_string);
|
||||||
JS_FreeValue(context, user_json);
|
JS_FreeValue(context, user_json);
|
||||||
@ -1678,70 +1681,47 @@ bool tf_ssb_db_set_account_password(uv_loop_t* loop, sqlite3* db, JSContext* con
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _tf_ssb_db_get_global_setting_bool(sqlite3* db, const char* name, bool default_value)
|
bool tf_ssb_db_register_account(tf_ssb_t* ssb, const char* name, const char* password)
|
||||||
{
|
{
|
||||||
bool result = default_value;
|
bool result = false;
|
||||||
sqlite3_stmt* statement;
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
if (sqlite3_prepare(db, "SELECT json_extract(value, '$.' || ?) FROM properties WHERE id = 'core' AND key = 'settings'", -1, &statement, NULL) == SQLITE_OK)
|
JSValue users_array = JS_UNDEFINED;
|
||||||
|
|
||||||
|
sqlite3* db = tf_ssb_acquire_db_writer(ssb);
|
||||||
|
sqlite3_stmt* statement = NULL;
|
||||||
|
if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = 'auth' AND key = 'users'", -1, &statement, NULL) == SQLITE_OK)
|
||||||
{
|
{
|
||||||
if (sqlite3_bind_text(statement, 1, name, -1, NULL) == SQLITE_OK)
|
if (sqlite3_step(statement) == SQLITE_ROW)
|
||||||
{
|
{
|
||||||
if (sqlite3_step(statement) == SQLITE_ROW && sqlite3_column_type(statement, 0) != SQLITE_NULL)
|
users_array = JS_ParseJSON(context, (const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0), NULL);
|
||||||
{
|
|
||||||
result = sqlite3_column_int(statement, 0) != 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sqlite3_finalize(statement);
|
sqlite3_finalize(statement);
|
||||||
}
|
}
|
||||||
else
|
if (JS_IsUndefined(users_array))
|
||||||
{
|
{
|
||||||
tf_printf("prepare failed: %s\n", sqlite3_errmsg(db));
|
users_array = JS_NewArray(context);
|
||||||
}
|
}
|
||||||
return result;
|
int length = tf_util_get_length(context, users_array);
|
||||||
}
|
JS_SetPropertyUint32(context, users_array, length, JS_NewString(context, name));
|
||||||
|
|
||||||
bool tf_ssb_db_register_account(uv_loop_t* loop, sqlite3* db, JSContext* context, const char* name, const char* password)
|
JSValue json = JS_JSONStringify(context, users_array, JS_NULL, JS_NULL);
|
||||||
{
|
JS_FreeValue(context, users_array);
|
||||||
bool result = false;
|
size_t value_length = 0;
|
||||||
JSValue users_array = JS_UNDEFINED;
|
const char* value = JS_ToCStringLen(context, &value_length, json);
|
||||||
|
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ('auth', 'users', ?)", -1, &statement, NULL) == SQLITE_OK)
|
||||||
bool registration_allowed = _tf_ssb_db_get_global_setting_bool(db, "account_registration", true);
|
|
||||||
if (registration_allowed)
|
|
||||||
{
|
{
|
||||||
sqlite3_stmt* statement = NULL;
|
if (sqlite3_bind_text(statement, 1, value, value_length, NULL) == SQLITE_OK)
|
||||||
if (sqlite3_prepare(db, "SELECT value FROM properties WHERE id = 'auth' AND key = 'users'", -1, &statement, NULL) == SQLITE_OK)
|
|
||||||
{
|
{
|
||||||
if (sqlite3_step(statement) == SQLITE_ROW)
|
tf_printf("added user to properties\n");
|
||||||
{
|
result = sqlite3_step(statement) == SQLITE_DONE;
|
||||||
users_array = JS_ParseJSON(context, (const char*)sqlite3_column_text(statement, 0), sqlite3_column_bytes(statement, 0), NULL);
|
|
||||||
}
|
|
||||||
sqlite3_finalize(statement);
|
|
||||||
}
|
}
|
||||||
if (JS_IsUndefined(users_array))
|
sqlite3_finalize(statement);
|
||||||
{
|
|
||||||
users_array = JS_NewArray(context);
|
|
||||||
}
|
|
||||||
int length = tf_util_get_length(context, users_array);
|
|
||||||
JS_SetPropertyUint32(context, users_array, length, JS_NewString(context, name));
|
|
||||||
|
|
||||||
JSValue json = JS_JSONStringify(context, users_array, JS_NULL, JS_NULL);
|
|
||||||
JS_FreeValue(context, users_array);
|
|
||||||
size_t value_length = 0;
|
|
||||||
const char* value = JS_ToCStringLen(context, &value_length, json);
|
|
||||||
if (sqlite3_prepare(db, "INSERT OR REPLACE INTO properties (id, key, value) VALUES ('auth', 'users', ?)", -1, &statement, NULL) == SQLITE_OK)
|
|
||||||
{
|
|
||||||
if (sqlite3_bind_text(statement, 1, value, value_length, NULL) == SQLITE_OK)
|
|
||||||
{
|
|
||||||
tf_printf("added user to properties\n");
|
|
||||||
result = sqlite3_step(statement) == SQLITE_DONE;
|
|
||||||
}
|
|
||||||
sqlite3_finalize(statement);
|
|
||||||
}
|
|
||||||
JS_FreeCString(context, value);
|
|
||||||
JS_FreeValue(context, json);
|
|
||||||
}
|
}
|
||||||
|
JS_FreeCString(context, value);
|
||||||
|
JS_FreeValue(context, json);
|
||||||
|
tf_ssb_release_db_writer(ssb, db);
|
||||||
|
|
||||||
result = result && tf_ssb_db_set_account_password(loop, db, context, name, password);
|
result = result && tf_ssb_db_set_account_password(ssb, name, password);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
src/ssb.db.h
12
src/ssb.db.h
@ -360,25 +360,21 @@ bool tf_ssb_db_get_account_password_hash(tf_ssb_t* ssb, const char* name, char*
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
** Insert or update a user's hashed password in the database.
|
** Insert or update a user's hashed password in the database.
|
||||||
** @param loop The event loop.
|
** @param ssb The SSB instance.
|
||||||
** @param db A DB writer.
|
|
||||||
** @param context A JS context.
|
|
||||||
** @param name The username.
|
** @param name The username.
|
||||||
** @param password The raw password.
|
** @param password The raw password.
|
||||||
** @return true if the hash of the password was successfully stored.
|
** @return true if the hash of the password was successfully stored.
|
||||||
*/
|
*/
|
||||||
bool tf_ssb_db_set_account_password(uv_loop_t* loop, sqlite3* db, JSContext* context, const char* name, const char* password);
|
bool tf_ssb_db_set_account_password(tf_ssb_t* ssb, const char* name, const char* password);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Add a user account to the database.
|
** Add a user account to the database.
|
||||||
** @param loop The event loop.
|
** @param ssb The SSB instance.
|
||||||
** @param db A DB writer.
|
|
||||||
** @param context A JS context.
|
|
||||||
** @param name The username to add.
|
** @param name The username to add.
|
||||||
** @param password The user's raw password.
|
** @param password The user's raw password.
|
||||||
** @return true If the user was added successfully.
|
** @return true If the user was added successfully.
|
||||||
*/
|
*/
|
||||||
bool tf_ssb_db_register_account(uv_loop_t* loop, sqlite3* db, JSContext* context, const char* name, const char* password);
|
bool tf_ssb_db_register_account(tf_ssb_t* ssb, const char* name, const char* password);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Get an entry from the properties table.
|
** Get an entry from the properties table.
|
||||||
|
54
src/ssb.h
54
src/ssb.h
@ -28,8 +28,6 @@ enum
|
|||||||
k_ssb_rpc_flag_new_request = 0x10,
|
k_ssb_rpc_flag_new_request = 0x10,
|
||||||
|
|
||||||
k_ssb_blob_bytes_max = 5 * 1024 * 1024,
|
k_ssb_blob_bytes_max = 5 * 1024 * 1024,
|
||||||
|
|
||||||
k_ssb_peer_exchange_expires_seconds = 60 * 60,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,16 +41,6 @@ typedef enum _tf_ssb_change_t
|
|||||||
k_tf_ssb_change_update,
|
k_tf_ssb_change_update,
|
||||||
} tf_ssb_change_t;
|
} tf_ssb_change_t;
|
||||||
|
|
||||||
/**
|
|
||||||
** The origin of a broadcast entry.
|
|
||||||
*/
|
|
||||||
typedef enum _tf_ssb_broadcast_origin_t
|
|
||||||
{
|
|
||||||
k_tf_ssb_broadcast_origin_discovery,
|
|
||||||
k_tf_ssb_broadcast_origin_room,
|
|
||||||
k_tf_ssb_broadcast_origin_peer_exchange,
|
|
||||||
} tf_ssb_broadcast_origin_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Flags describing the structure of a message.
|
** Flags describing the structure of a message.
|
||||||
*/
|
*/
|
||||||
@ -311,18 +299,8 @@ bool tf_ssb_whoami(tf_ssb_t* ssb, char* out_id, size_t out_id_size);
|
|||||||
** @param callback The callback.
|
** @param callback The callback.
|
||||||
** @param user_data User data for the callback.
|
** @param user_data User data for the callback.
|
||||||
*/
|
*/
|
||||||
void tf_ssb_visit_broadcasts(tf_ssb_t* ssb,
|
void tf_ssb_visit_broadcasts(
|
||||||
void (*callback)(const char* host, const struct sockaddr_in* addr, tf_ssb_broadcast_origin_t origin, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data),
|
tf_ssb_t* ssb, void (*callback)(const char* host, const struct sockaddr_in* addr, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data), void* user_data);
|
||||||
void* user_data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
** Add a broadcast entry.
|
|
||||||
** @param ssb The SSB instance.
|
|
||||||
** @param connection The connection string to add.
|
|
||||||
** @param origin The origin of the broadcast entry.
|
|
||||||
** @param expires_seconds How long the broadcast entry should last.
|
|
||||||
*/
|
|
||||||
void tf_ssb_add_broadcast(tf_ssb_t* ssb, const char* connection, tf_ssb_broadcast_origin_t origin, int64_t expires_seconds);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Get the identities of all active connections.
|
** Get the identities of all active connections.
|
||||||
@ -986,34 +964,6 @@ bool tf_ssb_is_room(tf_ssb_t* ssb);
|
|||||||
*/
|
*/
|
||||||
void tf_ssb_set_is_room(tf_ssb_t* ssb, bool is_room);
|
void tf_ssb_set_is_room(tf_ssb_t* ssb, bool is_room);
|
||||||
|
|
||||||
/**
|
|
||||||
** Get whether the running server supports replication of messages and blobs.
|
|
||||||
** @param ssb The SSB instance.
|
|
||||||
** @return True if the server is a replicator.
|
|
||||||
*/
|
|
||||||
bool tf_ssb_is_replicator(tf_ssb_t* ssb);
|
|
||||||
|
|
||||||
/**
|
|
||||||
** Set whether the running server supports replication of messages and blobs.
|
|
||||||
** @param ssb The SSB instance.
|
|
||||||
** @param is_replicator Whether to support replication.
|
|
||||||
*/
|
|
||||||
void tf_ssb_set_is_replicator(tf_ssb_t* ssb, bool is_replicator);
|
|
||||||
|
|
||||||
/**
|
|
||||||
** Get whether the running server participates in peer exchange.
|
|
||||||
** @param ssb The SSB instance.
|
|
||||||
** @return True if the server participates in peer exchange.
|
|
||||||
*/
|
|
||||||
bool tf_ssb_is_peer_exchange(tf_ssb_t* ssb);
|
|
||||||
|
|
||||||
/**
|
|
||||||
** Set whether the running server participates in peer exchange.
|
|
||||||
** @param ssb The SSB instance.
|
|
||||||
** @param is_peer_exchange Whether to participate in peer exchange.
|
|
||||||
*/
|
|
||||||
void tf_ssb_set_is_peer_exchange(tf_ssb_t* ssb, bool is_peer_exchange);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Get the name of the room hosted by the running server.
|
** Get the name of the room hosted by the running server.
|
||||||
** @param ssb The SSB instance.
|
** @param ssb The SSB instance.
|
||||||
|
@ -231,11 +231,7 @@ static void _tf_ssb_import_app_json(tf_ssb_t* ssb, uv_loop_t* loop, JSContext* c
|
|||||||
|
|
||||||
void tf_ssb_import(tf_ssb_t* ssb, const char* user, const char* path)
|
void tf_ssb_import(tf_ssb_t* ssb, const char* user, const char* path)
|
||||||
{
|
{
|
||||||
if (!path)
|
if (strlen(path) > strlen(".json") && strcasecmp(path + strlen(path) - strlen(".json"), ".json") == 0)
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (strlen(path) > strlen(".json") && strcasecmp(path + strlen(path) - strlen(".json"), ".json") == 0)
|
|
||||||
{
|
{
|
||||||
_tf_ssb_import_app_json(ssb, tf_ssb_get_loop(ssb), tf_ssb_get_context(ssb), user, path);
|
_tf_ssb_import_app_json(ssb, tf_ssb_get_loop(ssb), tf_ssb_get_context(ssb), user, path);
|
||||||
}
|
}
|
||||||
|
15
src/ssb.js.c
15
src/ssb.js.c
@ -1450,25 +1450,12 @@ typedef struct _broadcasts_t
|
|||||||
int length;
|
int length;
|
||||||
} broadcasts_t;
|
} broadcasts_t;
|
||||||
|
|
||||||
static void _tf_ssb_broadcasts_visit(
|
static void _tf_ssb_broadcasts_visit(const char* host, const struct sockaddr_in* addr, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data)
|
||||||
const char* host, const struct sockaddr_in* addr, tf_ssb_broadcast_origin_t origin, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data)
|
|
||||||
{
|
{
|
||||||
broadcasts_t* broadcasts = user_data;
|
broadcasts_t* broadcasts = user_data;
|
||||||
JSValue entry = JS_NewObject(broadcasts->context);
|
JSValue entry = JS_NewObject(broadcasts->context);
|
||||||
char pubkey[k_id_base64_len];
|
char pubkey[k_id_base64_len];
|
||||||
tf_ssb_id_bin_to_str(pubkey, sizeof(pubkey), pub);
|
tf_ssb_id_bin_to_str(pubkey, sizeof(pubkey), pub);
|
||||||
switch (origin)
|
|
||||||
{
|
|
||||||
case k_tf_ssb_broadcast_origin_discovery:
|
|
||||||
JS_SetPropertyStr(broadcasts->context, entry, "origin", JS_NewString(broadcasts->context, "discovery"));
|
|
||||||
break;
|
|
||||||
case k_tf_ssb_broadcast_origin_room:
|
|
||||||
JS_SetPropertyStr(broadcasts->context, entry, "origin", JS_NewString(broadcasts->context, "room"));
|
|
||||||
break;
|
|
||||||
case k_tf_ssb_broadcast_origin_peer_exchange:
|
|
||||||
JS_SetPropertyStr(broadcasts->context, entry, "origin", JS_NewString(broadcasts->context, "peer_exchange"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (tunnel)
|
if (tunnel)
|
||||||
{
|
{
|
||||||
JS_SetPropertyStr(broadcasts->context, entry, "tunnel", JS_DupValue(broadcasts->context, tf_ssb_connection_get_object(tunnel)));
|
JS_SetPropertyStr(broadcasts->context, entry, "tunnel", JS_DupValue(broadcasts->context, tf_ssb_connection_get_object(tunnel)));
|
||||||
|
231
src/ssb.rpc.c
231
src/ssb.rpc.c
@ -19,7 +19,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void _tf_ssb_connection_send_history_stream(tf_ssb_connection_t* connection, int32_t request_number, const char* author, int64_t sequence, bool keys, bool live);
|
static void _tf_ssb_connection_send_history_stream(tf_ssb_connection_t* connection, int32_t request_number, const char* author, int64_t sequence, bool keys, bool live);
|
||||||
static void _tf_ssb_rpc_send_peers_exchange(tf_ssb_connection_t* connection);
|
|
||||||
static void _tf_ssb_rpc_start_delete_blobs(tf_ssb_t* ssb, int delay_ms);
|
static void _tf_ssb_rpc_start_delete_blobs(tf_ssb_t* ssb, int delay_ms);
|
||||||
|
|
||||||
static int64_t _get_global_setting_int64(tf_ssb_t* ssb, const char* name, int64_t default_value)
|
static int64_t _get_global_setting_int64(tf_ssb_t* ssb, const char* name, int64_t default_value)
|
||||||
@ -108,12 +107,6 @@ static void _tf_ssb_rpc_blobs_get(tf_ssb_connection_t* connection, uint8_t flags
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
|
||||||
if (!tf_ssb_is_replicator(ssb))
|
|
||||||
{
|
|
||||||
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "blobs.get");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tf_ssb_connection_add_request(connection, -request_number, "blobs.get", _tf_ssb_rpc_blobs_get_callback, NULL, NULL, NULL);
|
tf_ssb_connection_add_request(connection, -request_number, "blobs.get", _tf_ssb_rpc_blobs_get_callback, NULL, NULL, NULL);
|
||||||
JSContext* context = tf_ssb_connection_get_context(connection);
|
JSContext* context = tf_ssb_connection_get_context(connection);
|
||||||
@ -148,51 +141,18 @@ static void _tf_ssb_rpc_blobs_get(tf_ssb_connection_t* connection, uint8_t flags
|
|||||||
JS_FreeValue(context, ids);
|
JS_FreeValue(context, ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _blobs_has_work_t
|
|
||||||
{
|
|
||||||
int64_t request_number;
|
|
||||||
char id[k_id_base64_len];
|
|
||||||
bool found;
|
|
||||||
} blobs_has_work_t;
|
|
||||||
|
|
||||||
static void _tf_ssb_rpc_blobs_has_work(tf_ssb_connection_t* connection, void* user_data)
|
|
||||||
{
|
|
||||||
blobs_has_work_t* work = user_data;
|
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
|
||||||
work->found = tf_ssb_db_blob_has(ssb, work->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _tf_ssb_rpc_blobs_has_after_work(tf_ssb_connection_t* connection, int status, void* user_data)
|
|
||||||
{
|
|
||||||
blobs_has_work_t* work = user_data;
|
|
||||||
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_json | k_ssb_rpc_flag_end_error | k_ssb_rpc_flag_stream, -work->request_number, NULL,
|
|
||||||
(const uint8_t*)(work->found ? "true" : "false"), strlen(work->found ? "true" : "false"), NULL, NULL, NULL);
|
|
||||||
tf_free(work);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _tf_ssb_rpc_blobs_has(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
static void _tf_ssb_rpc_blobs_has(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
||||||
if (!tf_ssb_is_replicator(ssb))
|
|
||||||
{
|
|
||||||
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "blobs.has");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
JSContext* context = tf_ssb_connection_get_context(connection);
|
JSContext* context = tf_ssb_connection_get_context(connection);
|
||||||
JSValue ids = JS_GetPropertyStr(context, args, "args");
|
JSValue ids = JS_GetPropertyStr(context, args, "args");
|
||||||
JSValue id = JS_GetPropertyUint32(context, ids, 0);
|
JSValue id = JS_GetPropertyUint32(context, ids, 0);
|
||||||
const char* id_str = JS_ToCString(context, id);
|
const char* id_str = JS_ToCString(context, id);
|
||||||
|
bool has = tf_ssb_db_blob_has(ssb, id_str);
|
||||||
blobs_has_work_t* work = tf_malloc(sizeof(blobs_has_work_t));
|
|
||||||
*work = (blobs_has_work_t) {
|
|
||||||
.request_number = request_number,
|
|
||||||
};
|
|
||||||
snprintf(work->id, sizeof(work->id), "%s", id_str);
|
|
||||||
tf_ssb_connection_run_work(connection, _tf_ssb_rpc_blobs_has_work, _tf_ssb_rpc_blobs_has_after_work, work);
|
|
||||||
|
|
||||||
JS_FreeCString(context, id_str);
|
JS_FreeCString(context, id_str);
|
||||||
JS_FreeValue(context, id);
|
JS_FreeValue(context, id);
|
||||||
JS_FreeValue(context, ids);
|
JS_FreeValue(context, ids);
|
||||||
|
tf_ssb_connection_rpc_send(connection, k_ssb_rpc_flag_json, -request_number, NULL, (const uint8_t*)(has ? "true" : "false"), strlen(has ? "true" : "false"), NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_ssb_rpc_blob_wants_added_callback(tf_ssb_t* ssb, const char* id, void* user_data)
|
static void _tf_ssb_rpc_blob_wants_added_callback(tf_ssb_t* ssb, const char* id, void* user_data)
|
||||||
@ -282,13 +242,8 @@ static void _tf_ssb_rpc_request_more_blobs(tf_ssb_connection_t* connection)
|
|||||||
static void _tf_ssb_rpc_blobs_createWants(
|
static void _tf_ssb_rpc_blobs_createWants(
|
||||||
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
|
||||||
if (!tf_ssb_is_replicator(ssb))
|
|
||||||
{
|
|
||||||
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "blobs.createWants");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection);
|
tf_ssb_blob_wants_t* blob_wants = tf_ssb_connection_get_blob_wants_state(connection);
|
||||||
|
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
||||||
tf_ssb_add_blob_want_added_callback(ssb, _tf_ssb_rpc_blob_wants_added_callback, NULL, connection);
|
tf_ssb_add_blob_want_added_callback(ssb, _tf_ssb_rpc_blob_wants_added_callback, NULL, connection);
|
||||||
blob_wants->request_number = request_number;
|
blob_wants->request_number = request_number;
|
||||||
_tf_ssb_rpc_request_more_blobs(connection);
|
_tf_ssb_rpc_request_more_blobs(connection);
|
||||||
@ -605,7 +560,6 @@ static void _tf_ssb_rpc_connection_blobs_createWants_callback(
|
|||||||
if (!JS_IsUndefined(name))
|
if (!JS_IsUndefined(name))
|
||||||
{
|
{
|
||||||
/* { name: "Error" } */
|
/* { name: "Error" } */
|
||||||
tf_ssb_connection_remove_request(connection, -request_number);
|
|
||||||
JS_FreeValue(context, name);
|
JS_FreeValue(context, name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -901,11 +855,6 @@ static void _tf_ssb_rpc_createHistoryStream(
|
|||||||
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
||||||
{
|
{
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
||||||
if (!tf_ssb_is_replicator(ssb))
|
|
||||||
{
|
|
||||||
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "createHistoryStream");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
JSContext* context = tf_ssb_get_context(ssb);
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
JSValue arg_array = JS_GetPropertyStr(context, args, "args");
|
JSValue arg_array = JS_GetPropertyStr(context, args, "args");
|
||||||
JSValue arg = JS_GetPropertyUint32(context, arg_array, 0);
|
JSValue arg = JS_GetPropertyUint32(context, arg_array, 0);
|
||||||
@ -1137,7 +1086,6 @@ static void _tf_ssb_rpc_ebt_replicate(tf_ssb_connection_t* connection, uint8_t f
|
|||||||
if (_is_error(context, args))
|
if (_is_error(context, args))
|
||||||
{
|
{
|
||||||
/* TODO: Send createHistoryStream. */
|
/* TODO: Send createHistoryStream. */
|
||||||
tf_ssb_connection_remove_request(connection, -request_number);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1209,12 +1157,6 @@ static void _tf_ssb_rpc_ebt_replicate_server(
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
|
||||||
if (!tf_ssb_is_replicator(ssb))
|
|
||||||
{
|
|
||||||
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "ebt.replicate");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_tf_ssb_rpc_ebt_replicate(connection, flags, request_number, args, message, size, user_data);
|
_tf_ssb_rpc_ebt_replicate(connection, flags, request_number, args, message, size, user_data);
|
||||||
tf_ssb_connection_add_request(connection, -request_number, "ebt.replicate", _tf_ssb_rpc_ebt_replicate, NULL, NULL, NULL);
|
tf_ssb_connection_add_request(connection, -request_number, "ebt.replicate", _tf_ssb_rpc_ebt_replicate, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
@ -1224,24 +1166,21 @@ static void _tf_ssb_rpc_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_chang
|
|||||||
JSContext* context = tf_ssb_get_context(ssb);
|
JSContext* context = tf_ssb_get_context(ssb);
|
||||||
if (change == k_tf_ssb_change_connect)
|
if (change == k_tf_ssb_change_connect)
|
||||||
{
|
{
|
||||||
if (tf_ssb_is_replicator(ssb))
|
JSValue message = JS_NewObject(context);
|
||||||
{
|
JSValue name = JS_NewArray(context);
|
||||||
JSValue message = JS_NewObject(context);
|
JS_SetPropertyUint32(context, name, 0, JS_NewString(context, "blobs"));
|
||||||
JSValue name = JS_NewArray(context);
|
JS_SetPropertyUint32(context, name, 1, JS_NewString(context, "createWants"));
|
||||||
JS_SetPropertyUint32(context, name, 0, JS_NewString(context, "blobs"));
|
JS_SetPropertyStr(context, message, "name", name);
|
||||||
JS_SetPropertyUint32(context, name, 1, JS_NewString(context, "createWants"));
|
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "source"));
|
||||||
JS_SetPropertyStr(context, message, "name", name);
|
JS_SetPropertyStr(context, message, "args", JS_NewArray(context));
|
||||||
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "source"));
|
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, tf_ssb_connection_next_request_number(connection), "blobs.createWants",
|
||||||
JS_SetPropertyStr(context, message, "args", JS_NewArray(context));
|
message, _tf_ssb_rpc_connection_blobs_createWants_callback, NULL, NULL);
|
||||||
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, tf_ssb_connection_next_request_number(connection), "blobs.createWants",
|
JS_FreeValue(context, message);
|
||||||
message, _tf_ssb_rpc_connection_blobs_createWants_callback, NULL, NULL);
|
|
||||||
JS_FreeValue(context, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tf_ssb_connection_is_client(connection))
|
if (tf_ssb_connection_is_client(connection))
|
||||||
{
|
{
|
||||||
JSValue message = JS_NewObject(context);
|
message = JS_NewObject(context);
|
||||||
JSValue name = JS_NewArray(context);
|
name = JS_NewArray(context);
|
||||||
JS_SetPropertyUint32(context, name, 0, JS_NewString(context, "tunnel"));
|
JS_SetPropertyUint32(context, name, 0, JS_NewString(context, "tunnel"));
|
||||||
JS_SetPropertyUint32(context, name, 1, JS_NewString(context, "isRoom"));
|
JS_SetPropertyUint32(context, name, 1, JS_NewString(context, "isRoom"));
|
||||||
JS_SetPropertyStr(context, message, "name", name);
|
JS_SetPropertyStr(context, message, "name", name);
|
||||||
@ -1250,15 +1189,7 @@ static void _tf_ssb_rpc_connections_changed_callback(tf_ssb_t* ssb, tf_ssb_chang
|
|||||||
_tf_ssb_rpc_connection_tunnel_isRoom_callback, NULL, NULL);
|
_tf_ssb_rpc_connection_tunnel_isRoom_callback, NULL, NULL);
|
||||||
JS_FreeValue(context, message);
|
JS_FreeValue(context, message);
|
||||||
|
|
||||||
if (tf_ssb_is_peer_exchange(ssb))
|
_tf_ssb_rpc_send_ebt_replicate(connection);
|
||||||
{
|
|
||||||
_tf_ssb_rpc_send_peers_exchange(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tf_ssb_is_replicator(ssb))
|
|
||||||
{
|
|
||||||
_tf_ssb_rpc_send_ebt_replicate(connection);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (change == k_tf_ssb_change_remove)
|
else if (change == k_tf_ssb_change_remove)
|
||||||
@ -1372,135 +1303,6 @@ void tf_ssb_rpc_start_periodic(tf_ssb_t* ssb)
|
|||||||
_tf_ssb_rpc_start_delete_blobs(ssb, 30 * 1000);
|
_tf_ssb_rpc_start_delete_blobs(ssb, 30 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _peers_exchange_t
|
|
||||||
{
|
|
||||||
tf_ssb_t* ssb;
|
|
||||||
JSValue peers;
|
|
||||||
} peers_exchange_t;
|
|
||||||
|
|
||||||
static void _tf_ssb_get_peers_exhange_callback(
|
|
||||||
const char* host, const struct sockaddr_in* addr, tf_ssb_broadcast_origin_t origin, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data)
|
|
||||||
{
|
|
||||||
peers_exchange_t* data = user_data;
|
|
||||||
if (origin == k_tf_ssb_broadcast_origin_peer_exchange)
|
|
||||||
{
|
|
||||||
char fullid[k_id_base64_len] = { 0 };
|
|
||||||
tf_base64_encode(pub, sizeof(pub), fullid, sizeof(fullid));
|
|
||||||
char* dot = strchr(fullid, '.');
|
|
||||||
if (dot)
|
|
||||||
{
|
|
||||||
*dot = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
char connection[1024] = { 0 };
|
|
||||||
snprintf(connection, sizeof(connection), "net:%s:%d~shs:%s", host, ntohs(addr->sin_port), fullid);
|
|
||||||
|
|
||||||
JSContext* context = tf_ssb_get_context(data->ssb);
|
|
||||||
JS_SetPropertyStr(context, data->peers, connection, JS_NewInt32(context, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static JSValue _tf_ssb_get_peers_exchange(tf_ssb_t* ssb)
|
|
||||||
{
|
|
||||||
JSContext* context = tf_ssb_get_context(ssb);
|
|
||||||
JSValue peers = JS_NewObject(context);
|
|
||||||
tf_ssb_visit_broadcasts(ssb, _tf_ssb_get_peers_exhange_callback, &(peers_exchange_t) { .ssb = ssb, .peers = peers });
|
|
||||||
return peers;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _tf_ssb_rpc_peers_exchange_internal(
|
|
||||||
tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
|
||||||
{
|
|
||||||
JSContext* context = tf_ssb_connection_get_context(connection);
|
|
||||||
if (_is_error(context, args))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The peer that participated in the exchange is now a peer exchange entry, too. */
|
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
|
||||||
if (*tf_ssb_connection_get_host(connection))
|
|
||||||
{
|
|
||||||
char fullid[k_id_base64_len] = { 0 };
|
|
||||||
tf_ssb_connection_get_id(connection, fullid, sizeof(fullid));
|
|
||||||
char* dot = strchr(fullid, '.');
|
|
||||||
if (dot)
|
|
||||||
{
|
|
||||||
*dot = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
char connection_string[1024] = { 0 };
|
|
||||||
snprintf(connection_string, sizeof(connection_string), "net:%s:%d~shs:%s", tf_ssb_connection_get_host(connection), tf_ssb_connection_get_port(connection), fullid + 1);
|
|
||||||
tf_ssb_add_broadcast(ssb, connection_string, k_tf_ssb_broadcast_origin_peer_exchange, k_ssb_peer_exchange_expires_seconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
JSValue in_peers = JS_GetPropertyStr(context, args, "peers");
|
|
||||||
|
|
||||||
JSPropertyEnum* ptab = NULL;
|
|
||||||
uint32_t plen = 0;
|
|
||||||
if (JS_GetOwnPropertyNames(context, &ptab, &plen, in_peers, JS_GPN_STRING_MASK) == 0)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < plen; ++i)
|
|
||||||
{
|
|
||||||
JSValue key = JS_AtomToString(context, ptab[i].atom);
|
|
||||||
JSPropertyDescriptor desc;
|
|
||||||
JSValue key_value = JS_NULL;
|
|
||||||
if (JS_GetOwnProperty(context, &desc, args, ptab[i].atom) == 1)
|
|
||||||
{
|
|
||||||
key_value = desc.value;
|
|
||||||
JS_FreeValue(context, desc.setter);
|
|
||||||
JS_FreeValue(context, desc.getter);
|
|
||||||
}
|
|
||||||
const char* connection = JS_ToCString(context, key);
|
|
||||||
int64_t timestamp = 0;
|
|
||||||
JS_ToInt64(context, ×tamp, key_value);
|
|
||||||
/* ADD BROADCAST connection: timestamp */
|
|
||||||
JS_FreeCString(context, connection);
|
|
||||||
JS_FreeValue(context, key);
|
|
||||||
JS_FreeValue(context, key_value);
|
|
||||||
}
|
|
||||||
for (uint32_t i = 0; i < plen; ++i)
|
|
||||||
{
|
|
||||||
JS_FreeAtom(context, ptab[i].atom);
|
|
||||||
}
|
|
||||||
js_free(context, ptab);
|
|
||||||
}
|
|
||||||
JS_FreeValue(context, in_peers);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _tf_ssb_rpc_send_peers_exchange(tf_ssb_connection_t* connection)
|
|
||||||
{
|
|
||||||
int32_t request_number = tf_ssb_connection_next_request_number(connection);
|
|
||||||
JSContext* context = tf_ssb_connection_get_context(connection);
|
|
||||||
JSValue message = JS_NewObject(context);
|
|
||||||
JSValue name = JS_NewArray(context);
|
|
||||||
JS_SetPropertyUint32(context, name, 0, JS_NewString(context, "peers"));
|
|
||||||
JS_SetPropertyUint32(context, name, 1, JS_NewString(context, "exchange"));
|
|
||||||
JS_SetPropertyStr(context, message, "name", name);
|
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
|
||||||
JS_SetPropertyStr(context, message, "peers", _tf_ssb_get_peers_exchange(ssb));
|
|
||||||
tf_ssb_connection_rpc_send_json(connection, k_ssb_rpc_flag_new_request, request_number, "peers.exchange", message, _tf_ssb_rpc_peers_exchange_internal, NULL, NULL);
|
|
||||||
JS_FreeValue(context, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _tf_ssb_rpc_peers_exchange(tf_ssb_connection_t* connection, uint8_t flags, int32_t request_number, JSValue args, const uint8_t* message, size_t size, void* user_data)
|
|
||||||
{
|
|
||||||
tf_ssb_t* ssb = tf_ssb_connection_get_ssb(connection);
|
|
||||||
if (!tf_ssb_is_peer_exchange(ssb))
|
|
||||||
{
|
|
||||||
tf_ssb_connection_rpc_send_error_method_not_allowed(connection, flags, -request_number, "peers.exchange");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_tf_ssb_rpc_peers_exchange_internal(connection, flags, request_number, args, message, size, user_data);
|
|
||||||
|
|
||||||
JSContext* context = tf_ssb_connection_get_context(connection);
|
|
||||||
JSValue out_message = JS_NewObject(context);
|
|
||||||
JS_SetPropertyStr(context, out_message, "peers", _tf_ssb_get_peers_exchange(ssb));
|
|
||||||
tf_ssb_connection_rpc_send_json(connection, flags, -request_number, NULL, out_message, NULL, NULL, NULL);
|
|
||||||
JS_FreeValue(context, out_message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tf_ssb_rpc_register(tf_ssb_t* ssb)
|
void tf_ssb_rpc_register(tf_ssb_t* ssb)
|
||||||
{
|
{
|
||||||
tf_ssb_add_connections_changed_callback(ssb, _tf_ssb_rpc_connections_changed_callback, NULL, NULL);
|
tf_ssb_add_connections_changed_callback(ssb, _tf_ssb_rpc_connections_changed_callback, NULL, NULL);
|
||||||
@ -1514,5 +1316,4 @@ void tf_ssb_rpc_register(tf_ssb_t* ssb)
|
|||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "room", "attendants", NULL }, _tf_ssb_rpc_room_attendants, NULL, NULL); /* SOURCE */
|
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "room", "attendants", NULL }, _tf_ssb_rpc_room_attendants, NULL, NULL); /* SOURCE */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "createHistoryStream", NULL }, _tf_ssb_rpc_createHistoryStream, NULL, NULL); /* SOURCE */
|
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "createHistoryStream", NULL }, _tf_ssb_rpc_createHistoryStream, NULL, NULL); /* SOURCE */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "ebt", "replicate", NULL }, _tf_ssb_rpc_ebt_replicate_server, NULL, NULL); /* DUPLEX */
|
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "ebt", "replicate", NULL }, _tf_ssb_rpc_ebt_replicate_server, NULL, NULL); /* DUPLEX */
|
||||||
tf_ssb_add_rpc_callback(ssb, (const char*[]) { "peers", "exchange", NULL }, _tf_ssb_rpc_peers_exchange, NULL, NULL); /* ASYNC */
|
|
||||||
}
|
}
|
||||||
|
115
src/ssb.tests.c
115
src/ssb.tests.c
@ -250,51 +250,22 @@ void tf_ssb_test_ssb(const tf_test_options_t* options)
|
|||||||
tf_printf("Waiting for connection.\n");
|
tf_printf("Waiting for connection.\n");
|
||||||
while (test.connection_count0 != 1 || test.connection_count1 != 1)
|
while (test.connection_count0 != 1 || test.connection_count1 != 1)
|
||||||
{
|
{
|
||||||
tf_ssb_set_main_thread(ssb0, true);
|
|
||||||
tf_ssb_set_main_thread(ssb1, true);
|
|
||||||
uv_run(&loop, UV_RUN_ONCE);
|
uv_run(&loop, UV_RUN_ONCE);
|
||||||
tf_ssb_set_main_thread(ssb0, false);
|
|
||||||
tf_ssb_set_main_thread(ssb1, false);
|
|
||||||
}
|
}
|
||||||
tf_ssb_server_close(ssb0);
|
tf_ssb_server_close(ssb0);
|
||||||
|
|
||||||
tf_printf("Waiting for messages.\n");
|
tf_printf("Waiting for messages.\n");
|
||||||
while (_ssb_test_count_messages(ssb1) < 3)
|
while (_ssb_test_count_messages(ssb1) < 3)
|
||||||
{
|
{
|
||||||
tf_ssb_set_main_thread(ssb0, true);
|
|
||||||
tf_ssb_set_main_thread(ssb1, true);
|
|
||||||
uv_run(&loop, UV_RUN_ONCE);
|
uv_run(&loop, UV_RUN_ONCE);
|
||||||
tf_ssb_set_main_thread(ssb0, false);
|
|
||||||
tf_ssb_set_main_thread(ssb1, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tf_printf("Waiting for blob.\n");
|
tf_printf("Waiting for blob.\n");
|
||||||
while (!tf_ssb_db_blob_get(ssb1, blob_id, NULL, NULL))
|
while (!tf_ssb_db_blob_get(ssb1, blob_id, NULL, NULL))
|
||||||
{
|
{
|
||||||
tf_ssb_set_main_thread(ssb0, true);
|
|
||||||
tf_ssb_set_main_thread(ssb1, true);
|
|
||||||
uv_run(&loop, UV_RUN_ONCE);
|
uv_run(&loop, UV_RUN_ONCE);
|
||||||
tf_ssb_set_main_thread(ssb0, false);
|
|
||||||
tf_ssb_set_main_thread(ssb1, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSContext* context = tf_ssb_get_context(ssb1);
|
|
||||||
JSValue message = JS_NewObject(context);
|
|
||||||
JSValue name = JS_NewArray(context);
|
|
||||||
JS_SetPropertyUint32(context, name, 0, JS_NewString(context, "blobs"));
|
|
||||||
JS_SetPropertyUint32(context, name, 1, JS_NewString(context, "has"));
|
|
||||||
JS_SetPropertyStr(context, message, "name", name);
|
|
||||||
JSValue args = JS_NewArray(context);
|
|
||||||
JS_SetPropertyUint32(context, args, 0, JS_NewString(context, blob_id));
|
|
||||||
JS_SetPropertyStr(context, message, "args", args);
|
|
||||||
JS_SetPropertyStr(context, message, "type", JS_NewString(context, "async"));
|
|
||||||
|
|
||||||
tf_ssb_connection_t* connections[4] = { 0 };
|
|
||||||
tf_ssb_get_connections(ssb1, connections, 4);
|
|
||||||
int64_t request_number = tf_ssb_connection_next_request_number(connections[0]);
|
|
||||||
tf_ssb_connection_rpc_send_json(connections[0], k_ssb_rpc_flag_stream | k_ssb_rpc_flag_new_request, request_number, "blobs.has", message, NULL, NULL, NULL);
|
|
||||||
JS_FreeValue(context, message);
|
|
||||||
|
|
||||||
uint8_t* b1;
|
uint8_t* b1;
|
||||||
size_t s1 = 0;
|
size_t s1 = 0;
|
||||||
b = tf_ssb_db_blob_get(ssb1, blob_id, &b1, &s1);
|
b = tf_ssb_db_blob_get(ssb1, blob_id, &b1, &s1);
|
||||||
@ -322,22 +293,14 @@ void tf_ssb_test_ssb(const tf_test_options_t* options)
|
|||||||
|
|
||||||
while (count0 == 0)
|
while (count0 == 0)
|
||||||
{
|
{
|
||||||
tf_ssb_set_main_thread(ssb0, true);
|
|
||||||
tf_ssb_set_main_thread(ssb1, true);
|
|
||||||
uv_run(&loop, UV_RUN_ONCE);
|
uv_run(&loop, UV_RUN_ONCE);
|
||||||
tf_ssb_set_main_thread(ssb0, false);
|
|
||||||
tf_ssb_set_main_thread(ssb1, false);
|
|
||||||
}
|
}
|
||||||
tf_ssb_remove_message_added_callback(ssb0, _message_added, &count0);
|
tf_ssb_remove_message_added_callback(ssb0, _message_added, &count0);
|
||||||
|
|
||||||
tf_printf("Waiting for message from other.\n");
|
tf_printf("Waiting for message from other.\n");
|
||||||
while (count1 == 0)
|
while (count1 == 0)
|
||||||
{
|
{
|
||||||
tf_ssb_set_main_thread(ssb0, true);
|
|
||||||
tf_ssb_set_main_thread(ssb1, true);
|
|
||||||
uv_run(&loop, UV_RUN_ONCE);
|
uv_run(&loop, UV_RUN_ONCE);
|
||||||
tf_ssb_set_main_thread(ssb0, false);
|
|
||||||
tf_ssb_set_main_thread(ssb1, false);
|
|
||||||
}
|
}
|
||||||
tf_ssb_remove_message_added_callback(ssb1, _message_added, &count1);
|
tf_ssb_remove_message_added_callback(ssb1, _message_added, &count1);
|
||||||
tf_printf("done\n");
|
tf_printf("done\n");
|
||||||
@ -348,11 +311,7 @@ void tf_ssb_test_ssb(const tf_test_options_t* options)
|
|||||||
uv_close((uv_handle_t*)&idle1, NULL);
|
uv_close((uv_handle_t*)&idle1, NULL);
|
||||||
|
|
||||||
tf_printf("final run\n");
|
tf_printf("final run\n");
|
||||||
tf_ssb_set_main_thread(ssb0, true);
|
|
||||||
tf_ssb_set_main_thread(ssb1, true);
|
|
||||||
uv_run(&loop, UV_RUN_DEFAULT);
|
uv_run(&loop, UV_RUN_DEFAULT);
|
||||||
tf_ssb_set_main_thread(ssb0, false);
|
|
||||||
tf_ssb_set_main_thread(ssb1, false);
|
|
||||||
tf_printf("done\n");
|
tf_printf("done\n");
|
||||||
|
|
||||||
tf_printf("destroy 0\n");
|
tf_printf("destroy 0\n");
|
||||||
@ -364,7 +323,7 @@ void tf_ssb_test_ssb(const tf_test_options_t* options)
|
|||||||
uv_loop_close(&loop);
|
uv_loop_close(&loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _broadcasts_visit(const char* host, const struct sockaddr_in* addr, tf_ssb_broadcast_origin_t origin, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data)
|
static void _broadcasts_visit(const char* host, const struct sockaddr_in* addr, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data)
|
||||||
{
|
{
|
||||||
int* count = user_data;
|
int* count = user_data;
|
||||||
(*count)++;
|
(*count)++;
|
||||||
@ -788,8 +747,7 @@ static void _break_in_a_bit(tf_ssb_t* ssb, tf_ssb_connection_t* connection, cons
|
|||||||
uv_timer_start(&data->timer, _close_callback, 3000, 0);
|
uv_timer_start(&data->timer, _close_callback, 3000, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _ssb_test_room_broadcasts_visit(
|
static void _ssb_test_room_broadcasts_visit(const char* host, const struct sockaddr_in* addr, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data)
|
||||||
const char* host, const struct sockaddr_in* addr, tf_ssb_broadcast_origin_t origin, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data)
|
|
||||||
{
|
{
|
||||||
tf_ssb_t* ssb = user_data;
|
tf_ssb_t* ssb = user_data;
|
||||||
char id[k_id_base64_len] = { 0 };
|
char id[k_id_base64_len] = { 0 };
|
||||||
@ -911,73 +869,4 @@ void tf_ssb_test_encrypt(const tf_test_options_t* options)
|
|||||||
printf("returned %d\n", WEXITSTATUS(result));
|
printf("returned %d\n", WEXITSTATUS(result));
|
||||||
assert(WEXITSTATUS(result) == 0);
|
assert(WEXITSTATUS(result) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _count_broadcasts_callback(
|
|
||||||
const char* host, const struct sockaddr_in* addr, tf_ssb_broadcast_origin_t origin, tf_ssb_connection_t* tunnel, const uint8_t* pub, void* user_data)
|
|
||||||
{
|
|
||||||
int* count = user_data;
|
|
||||||
(*count)++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _count_broadcasts(tf_ssb_t* ssb)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
tf_ssb_visit_broadcasts(ssb, _count_broadcasts_callback, &count);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tf_ssb_test_peer_exchange(const tf_test_options_t* options)
|
|
||||||
{
|
|
||||||
uv_loop_t loop = { 0 };
|
|
||||||
uv_loop_init(&loop);
|
|
||||||
|
|
||||||
unlink("out/test_db0.sqlite");
|
|
||||||
tf_ssb_t* ssb0 = tf_ssb_create(&loop, NULL, "file:out/test_db0.sqlite", NULL);
|
|
||||||
tf_ssb_set_is_room(ssb0, false);
|
|
||||||
tf_ssb_set_is_replicator(ssb0, false);
|
|
||||||
tf_ssb_set_is_peer_exchange(ssb0, true);
|
|
||||||
tf_ssb_register(tf_ssb_get_context(ssb0), ssb0);
|
|
||||||
tf_ssb_server_open(ssb0, 12347);
|
|
||||||
|
|
||||||
unlink("out/test_db1.sqlite");
|
|
||||||
tf_ssb_t* ssb1 = tf_ssb_create(&loop, NULL, "file:out/test_db1.sqlite", NULL);
|
|
||||||
tf_ssb_set_is_room(ssb1, false);
|
|
||||||
tf_ssb_set_is_replicator(ssb1, false);
|
|
||||||
tf_ssb_set_is_peer_exchange(ssb1, true);
|
|
||||||
tf_ssb_register(tf_ssb_get_context(ssb1), ssb1);
|
|
||||||
tf_ssb_server_open(ssb1, 12348);
|
|
||||||
|
|
||||||
unlink("out/test_db2.sqlite");
|
|
||||||
tf_ssb_t* ssb2 = tf_ssb_create(&loop, NULL, "file:out/test_db2.sqlite", NULL);
|
|
||||||
tf_ssb_set_is_room(ssb2, false);
|
|
||||||
tf_ssb_set_is_replicator(ssb2, false);
|
|
||||||
tf_ssb_set_is_peer_exchange(ssb2, true);
|
|
||||||
tf_ssb_register(tf_ssb_get_context(ssb2), ssb2);
|
|
||||||
tf_ssb_server_open(ssb2, 12349);
|
|
||||||
|
|
||||||
char id0[k_id_base64_len] = { 0 };
|
|
||||||
tf_ssb_whoami(ssb0, id0, sizeof(id0));
|
|
||||||
uint8_t id0bin[k_id_bin_len];
|
|
||||||
tf_ssb_id_str_to_bin(id0bin, id0);
|
|
||||||
tf_ssb_connect(ssb1, "127.0.0.1", 12347, id0bin);
|
|
||||||
tf_ssb_connect(ssb2, "127.0.0.1", 12347, id0bin);
|
|
||||||
|
|
||||||
while (_count_broadcasts(ssb0) != 2 || _count_broadcasts(ssb1) != 1 || _count_broadcasts(ssb2) != 1)
|
|
||||||
{
|
|
||||||
uv_run(&loop, UV_RUN_ONCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
tf_ssb_send_close(ssb0);
|
|
||||||
tf_ssb_send_close(ssb1);
|
|
||||||
tf_ssb_send_close(ssb2);
|
|
||||||
|
|
||||||
tf_ssb_destroy(ssb0);
|
|
||||||
tf_ssb_destroy(ssb1);
|
|
||||||
tf_ssb_destroy(ssb2);
|
|
||||||
|
|
||||||
uv_run(&loop, UV_RUN_DEFAULT);
|
|
||||||
|
|
||||||
uv_loop_close(&loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -53,10 +53,4 @@ void tf_ssb_test_go_ssb_room(const tf_test_options_t* options);
|
|||||||
*/
|
*/
|
||||||
void tf_ssb_test_encrypt(const tf_test_options_t* options);
|
void tf_ssb_test_encrypt(const tf_test_options_t* options);
|
||||||
|
|
||||||
/**
|
|
||||||
** Test peer exchange.
|
|
||||||
** @param options The test options.
|
|
||||||
*/
|
|
||||||
void tf_ssb_test_peer_exchange(const tf_test_options_t* options);
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
38
src/task.c
38
src/task.c
@ -140,7 +140,8 @@ typedef struct _tf_task_t
|
|||||||
float idle_percent;
|
float idle_percent;
|
||||||
float thread_percent;
|
float thread_percent;
|
||||||
|
|
||||||
uv_async_t run_jobs_async;
|
uv_idle_t idle;
|
||||||
|
uv_prepare_t prepare;
|
||||||
uv_signal_t sig_term;
|
uv_signal_t sig_term;
|
||||||
uv_signal_t sig_int;
|
uv_signal_t sig_int;
|
||||||
|
|
||||||
@ -207,6 +208,7 @@ static void _tf_task_sendPromiseExportMessage(tf_task_t* from, tf_taskstub_t* to
|
|||||||
static JSValue _tf_task_executeSource(tf_task_t* task, const char* source, const char* name);
|
static JSValue _tf_task_executeSource(tf_task_t* task, const char* source, const char* name);
|
||||||
static tf_taskstub_t* _tf_task_get_stub(tf_task_t* task, taskid_t id);
|
static tf_taskstub_t* _tf_task_get_stub(tf_task_t* task, taskid_t id);
|
||||||
static void _tf_task_release_export(tf_taskstub_t* stub, exportid_t exportId);
|
static void _tf_task_release_export(tf_taskstub_t* stub, exportid_t exportId);
|
||||||
|
static void _tf_task_run_jobs_prepare(uv_prepare_t* prepare);
|
||||||
static void _timeout_unlink(tf_task_t* task, timeout_t* timeout);
|
static void _timeout_unlink(tf_task_t* task, timeout_t* timeout);
|
||||||
static void _timeout_closed(uv_handle_t* handle);
|
static void _timeout_closed(uv_handle_t* handle);
|
||||||
|
|
||||||
@ -1519,20 +1521,25 @@ static bool _tf_task_run_jobs(tf_task_t* task)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _tf_task_run_jobs_async(uv_async_t* async)
|
static void _tf_task_run_jobs_idle(uv_idle_t* idle)
|
||||||
{
|
{
|
||||||
tf_task_t* task = async->data;
|
tf_task_t* task = idle->data;
|
||||||
if (_tf_task_run_jobs(task))
|
if (!_tf_task_run_jobs(task))
|
||||||
{
|
{
|
||||||
uv_async_send(async);
|
/* No more jobs. Don't try again as actively. */
|
||||||
|
uv_idle_stop(&task->idle);
|
||||||
|
uv_prepare_start(&task->prepare, _tf_task_run_jobs_prepare);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tf_task_check_jobs(tf_task_t* task)
|
static void _tf_task_run_jobs_prepare(uv_prepare_t* prepare)
|
||||||
{
|
{
|
||||||
if (JS_IsJobPending(task->_runtime))
|
tf_task_t* task = prepare->data;
|
||||||
|
if (_tf_task_run_jobs(task))
|
||||||
{
|
{
|
||||||
uv_async_send(&task->run_jobs_async);
|
/* More jobs. We can run again immediately. */
|
||||||
|
uv_idle_start(&task->idle, _tf_task_run_jobs_idle);
|
||||||
|
uv_prepare_stop(&task->prepare);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1629,9 +1636,13 @@ tf_task_t* tf_task_create()
|
|||||||
uv_timer_init(&task->_loop, &task->gc_timer);
|
uv_timer_init(&task->_loop, &task->gc_timer);
|
||||||
uv_timer_start(&task->gc_timer, _tf_task_gc_timer, 1000, 1000);
|
uv_timer_start(&task->gc_timer, _tf_task_gc_timer, 1000, 1000);
|
||||||
uv_unref((uv_handle_t*)&task->gc_timer);
|
uv_unref((uv_handle_t*)&task->gc_timer);
|
||||||
task->run_jobs_async.data = task;
|
task->idle.data = task;
|
||||||
uv_async_init(&task->_loop, &task->run_jobs_async, _tf_task_run_jobs_async);
|
uv_idle_init(&task->_loop, &task->idle);
|
||||||
uv_unref((uv_handle_t*)&task->run_jobs_async);
|
uv_unref((uv_handle_t*)&task->idle);
|
||||||
|
task->prepare.data = task;
|
||||||
|
uv_prepare_init(&task->_loop, &task->prepare);
|
||||||
|
uv_unref((uv_handle_t*)&task->prepare);
|
||||||
|
uv_idle_start(&task->idle, _tf_task_run_jobs_idle);
|
||||||
task->sig_term.data = task;
|
task->sig_term.data = task;
|
||||||
uv_signal_init(&task->_loop, &task->sig_term);
|
uv_signal_init(&task->_loop, &task->sig_term);
|
||||||
uv_signal_start(&task->sig_term, _tf_task_signal_shutdown, SIGTERM);
|
uv_signal_start(&task->sig_term, _tf_task_signal_shutdown, SIGTERM);
|
||||||
@ -1899,13 +1910,14 @@ void tf_task_destroy(tf_task_t* task)
|
|||||||
{
|
{
|
||||||
uv_close((uv_handle_t*)&task->gc_timer, _tf_task_on_handle_close);
|
uv_close((uv_handle_t*)&task->gc_timer, _tf_task_on_handle_close);
|
||||||
}
|
}
|
||||||
uv_close((uv_handle_t*)&task->run_jobs_async, _tf_task_on_handle_close);
|
uv_close((uv_handle_t*)&task->idle, _tf_task_on_handle_close);
|
||||||
|
uv_close((uv_handle_t*)&task->prepare, _tf_task_on_handle_close);
|
||||||
uv_signal_stop(&task->sig_term);
|
uv_signal_stop(&task->sig_term);
|
||||||
uv_close((uv_handle_t*)&task->sig_term, _tf_task_on_handle_close);
|
uv_close((uv_handle_t*)&task->sig_term, _tf_task_on_handle_close);
|
||||||
uv_signal_stop(&task->sig_int);
|
uv_signal_stop(&task->sig_int);
|
||||||
uv_close((uv_handle_t*)&task->sig_int, _tf_task_on_handle_close);
|
uv_close((uv_handle_t*)&task->sig_int, _tf_task_on_handle_close);
|
||||||
|
|
||||||
while (task->trace_timer.data || task->gc_timer.data || task->run_jobs_async.data || task->sig_term.data || task->sig_int.data)
|
while (task->trace_timer.data || task->gc_timer.data || task->idle.data || task->prepare.data || task->sig_term.data || task->sig_int.data)
|
||||||
{
|
{
|
||||||
uv_run(&task->_loop, UV_RUN_ONCE);
|
uv_run(&task->_loop, UV_RUN_ONCE);
|
||||||
}
|
}
|
||||||
|
@ -364,11 +364,4 @@ tf_android_start_service_t* tf_task_get_android_start_service();
|
|||||||
*/
|
*/
|
||||||
tf_android_stop_service_t* tf_task_get_android_stop_service();
|
tf_android_stop_service_t* tf_task_get_android_stop_service();
|
||||||
|
|
||||||
/**
|
|
||||||
** Check for JS jobs that need to be run. Generally to be called post-JS_Call
|
|
||||||
** in tf_util_report_error.
|
|
||||||
** @param task The task.
|
|
||||||
*/
|
|
||||||
void tf_task_check_jobs(tf_task_t* task);
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@ -915,7 +915,6 @@ void tf_tests(const tf_test_options_t* options)
|
|||||||
_tf_test_run(options, "auto", _test_auto, false);
|
_tf_test_run(options, "auto", _test_auto, false);
|
||||||
_tf_test_run(options, "go-ssb-room", tf_ssb_test_go_ssb_room, true);
|
_tf_test_run(options, "go-ssb-room", tf_ssb_test_go_ssb_room, true);
|
||||||
_tf_test_run(options, "encrypt", tf_ssb_test_encrypt, false);
|
_tf_test_run(options, "encrypt", tf_ssb_test_encrypt, false);
|
||||||
_tf_test_run(options, "peer_exchange", tf_ssb_test_peer_exchange, false);
|
|
||||||
tf_printf("Tests completed.\n");
|
tf_printf("Tests completed.\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,6 @@ static JSValue _util_print(JSContext* context, JSValueConst this_val, int argc,
|
|||||||
bool tf_util_report_error(JSContext* context, JSValue value)
|
bool tf_util_report_error(JSContext* context, JSValue value)
|
||||||
{
|
{
|
||||||
bool is_error = false;
|
bool is_error = false;
|
||||||
tf_task_t* task = tf_task_get(context);
|
|
||||||
if (JS_IsError(context, value))
|
if (JS_IsError(context, value))
|
||||||
{
|
{
|
||||||
const char* string = JS_ToCString(context, value);
|
const char* string = JS_ToCString(context, value);
|
||||||
@ -227,11 +226,13 @@ bool tf_util_report_error(JSContext* context, JSValue value)
|
|||||||
}
|
}
|
||||||
JS_FreeValue(context, stack);
|
JS_FreeValue(context, stack);
|
||||||
|
|
||||||
|
tf_task_t* task = tf_task_get(context);
|
||||||
tf_task_send_error_to_parent(task, value);
|
tf_task_send_error_to_parent(task, value);
|
||||||
is_error = true;
|
is_error = true;
|
||||||
}
|
}
|
||||||
else if (JS_IsException(value))
|
else if (JS_IsException(value))
|
||||||
{
|
{
|
||||||
|
tf_task_t* task = tf_task_get(context);
|
||||||
if (!tf_task_send_error_to_parent(task, value))
|
if (!tf_task_send_error_to_parent(task, value))
|
||||||
{
|
{
|
||||||
JSValue exception = JS_GetException(context);
|
JSValue exception = JS_GetException(context);
|
||||||
@ -240,7 +241,6 @@ bool tf_util_report_error(JSContext* context, JSValue value)
|
|||||||
}
|
}
|
||||||
is_error = true;
|
is_error = true;
|
||||||
}
|
}
|
||||||
tf_task_check_jobs(task);
|
|
||||||
return is_error;
|
return is_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user