Conversation
…enewal deferral - rotating_seed doc (C++ and C): "as of now" instead of "contains now"; drop the epoch-computation narration and the redundant naming rationale. - pro_renewal_target: promote the boundary defer / min-validity magic values to documented constants -- PRO_RENEWAL_BOUNDARY_DEFER (reduced 2min -> 1min) and PRO_RENEWAL_BOUNDARY_MIN_VALIDITY (5min) -- and reword the collision comment to just say a collision is resolved by config resolution rather than (incorrectly) describing how config resolves it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the C-style utf16_count_truncated_to_codepoints (span in, code-unit index out) with utf16_truncate(u16string_view) -> u16string_view returning the truncated prefix directly, and take utf16_count on a u16string_view. Remove the assert()s on the surrogate state (invalid UTF-16 is documented-but-UB *input*, not a programming invariant, so asserting on it is wrong) and the now-dead surrogate helpers. Rename utf8_truncate's `n` to `max_bytes`. Tests use native u"..." literals instead of a UTF-8->UTF-16 round-trip UDL. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The utf8/16 variants forced libsession to validate and codepoint-count the message text, but every client already counts codepoints natively. Take the count directly via pro_features_for_message(size_t codepoint_count) and keep only the policy libsession should own: the character-limit thresholds and the count->flag mapping. Drops the simdutf validation/count (and the simdutf include, its only user in this TU), the redundant codepoint_count output field, and the now-impossible UTFDecodingError status. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ter TODO Same doc correction as dev: the 7-day rotating_seed quantization is not a "weekly rotation period" -- rotation cadence is the backend-issued proof expiry (min of subscription remaining, 30 days), and the 7-day bucket only makes every device agree on the derived seed. Also adds a TODO in pro_renewal_target to investigate device-count-aware renewal jitter (skewed so the first-order statistic is uniform, using PFS's multi-device account info) so the public renewal-time distribution can't leak the device count -- the dev branch can't (count unknown there) and accepts the lesser backend-only leak. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… signal
pro_renewal_target returned `now` (fetch immediately) for *any* missing or
expired proof, which told a non-Pro account -- and a lapsed one -- to hammer the
backend indefinitely. Split the two cases:
- no proof at all: fetch only if a purchase is in flight (the prepaid marker),
else nullopt. An entitled account carries its proof in synced config `s`, so
genuinely having none means the account isn't Pro.
- present-but-expired proof: always re-check. The subscription may have
auto-renewed without this device's knowledge (a stale cached access expiry
can't be trusted), and on an authoritative not-Pro the client clears the
credential -- which terminates the loop.
Also corrects a stray "weekly rotation" mischaracterization in a test comment.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
generate_pro_proof responses now carry account_expiry_ts -- the account's true, grace-inclusive entitlement end (the same value get_pro_status returns), distinct from the proof's own clamped <=30d expiry_ts. It rides the response so a proof fetch also refreshes the client's cached access expiry. Exposed on GenerateProProofResponse (C++, optional) and session_pro_backend_pro_proof_response (C, 0 when absent). Advisory and unsigned: never fed into signature verification -- M is reconstructed from version/revocation_tag/rotating_pkey/expiry_ts only (pro-wire-protocol.md §2.2). Required on a successful proof; also read top-level off a subscription_expired failure so an expired-sub client can refresh its horizon without a separate get_pro_status; absent on not_subscribed / revoked. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Pro backend (>= 0.3.0) sizes the padding on its per-account proof-expiry grid around exactly this 1h renewal lead, so `expiry_ts - PRO_RENEWAL_LEAD` lands just after the subscription's grace-inclusive true end. Increasing the lead (renewing earlier than 1h before expiry) would reach the upstream store before its final chance to report a renewal and get a spurious subscription_expired, so it now requires a coordinated backend change. Comment only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(PFS) Pro: atomic credential storage; key rotation & renewal logic; add_pro_payment renewal
The backend no longer reports a redeemed timestamp: no client uses it and it exposes an internal payment-lifecycle detail with no purpose here. The "unredeemed" status string is likewise gone: anything that could return it redeems the payment before returning, so the value was never actually observable. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(PFS) Drop redeemed_at/redeemed_ts and the "unredeemed" status
The backend renamed the out-of-band grant provider from "rangeproof" to
"stf", reflecting that such issuances come from the Session Technology
Foundation, not the inactive Rangeproof dev house. Follow the wire/slug
value ("stf") and the C/C++ constant names to match.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(PFS) Rename payment provider rangeproof -> stf
Forward-port of #109 (dev commits c3f6951..b08630b) onto pfs. session_id_matches_blinded_id() read blinded_id[1] before checking the value's length, and never checked that it was hex. It also used the predicate `blinded_id[1] != '5' && (blinded_id[0] != '1' || blinded_id[0] != '2')`, whose right-hand side is always true (a char cannot differ from both '1' and '2' only when it equals one of them, so the || is tautological), leaving the check as just `blinded_id[1] != '5'` -- so any X5-prefixed value, including a plain 05 session id, was accepted as a blinded id. Validate length and hex before indexing, and replace the prefix tests with starts_with("15")/starts_with("25"). Applies to pfs unmodified: line-for-line identical to the dev change.
Records dev up to 4a47113 as merged, keeping pfs's tree unchanged (-s ours). Everything in the range is already applied to pfs: - #104 (refund-requested-config) via #106 refund-requested-config-pfs - #107 (drop-redeemed-at) via #108 drop-redeemed-at-pfs - #110 (rename-rp-to-stf) via #111 rename-rp-to-stf-pfs - #109 (fix-blinded-id-validation) forward-ported in the preceding commit The first three were rewritten for pfs and so have different patch-ids, which is why `git cherry` still reports their commits as absent; the content was verified present by comparing the identifiers each PR added or removed across both branches.
The backend is dropping this field and libsession follows. It carried no actionable information: a single count of "some number of backend errors happened at some unspecified past time", with no what, no when, and nothing a client could do in response. Parsing it only added a way for the response to fail. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the manual skip_until + consume_string_view + explicit size checks with require<>/require_span<>/maybe<>, which fold presence and size/type validation into the accessor. Build the verification buffer with reserve+insert instead of resize+memcpy (identical bytes; also drops the spurious -Wstringop-overflow warning on the memcpy).
(PFS) Drop error_report from get_pro_status
Records dev up to 947d72a as merged, keeping pfs's tree unchanged (-s ours). The only PR in the range, #112 (drop-error-report), is already applied to pfs via #113 drop-error-report-pfs; nothing needed forward-porting. #113 is a faithful adaptation rather than a straight pick, so its commits have different patch-ids: it carries the same six files, differing only in pfs's unsigned char -> std::byte types, the resulting drop of an ed_pk.first<32>() now that require_span is fixed-extent, and each branch removing its own pre-existing form of the two size-error messages. Verified by outcome: error_report is absent from both branches, both parse decrypt_group_message through the bt_dict_consumer require/maybe helpers, and seed_payment.py is identical on both.
The proof/status/payment/revocation parsers threaded a std::vector<std::string> of errors through every helper and made the caller check it afterwards -- C-style error handling in C++. Replace it with a `parse_error` exception (new, public in pro_backend.hpp): the JSON helpers and each parser throw on a malformed reply, while a well-formed backend *failure* (envelope status fail/error) is still returned normally with status/error_code set. The C entry points catch once and translate to the invalid_response header, now carrying the real diagnostic rather than a fixed "out-of-memory" string. Along the way: - json_require<double> accepts any JSON number (is_number(), since an integer is a valid float value) rather than is_number_float(); the now-redundant json_require_number helper is removed. - json_require<integral> uses is_number_integer() so a fractional wire value is rejected rather than silently truncated by get_to. - rename json_require_fixed_bytes_from_hex -> json_require_hex. - C-layer allocations use make_unique + release() rather than a raw new with a manual delete in the catch; this also closes a leak in the error-translation path where a throw between the new and the pointer assignment orphaned the object. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
pro_renewal_target returned nullopt ("never (re)fetch") whenever there was
no proof credential unless a prepaid purchase marker was set. But `s` (the
credential) and `E` (the access expiry) are independent config keys, so an
account can be genuinely entitled -- `E` still in the future -- while
holding no proof (e.g. `s` was dropped or merge-lost). That state should
fetch a proof, not sit idle forever. Return `now` when the access expiry is
still in the future and there's no proof.
Also rename the local `pro` -> `pro_config`: it is the full ProConfig
credential (rotating key + proof), not a boolean "are we pro", and the old
name misled at least one reader into misdiagnosing this very path.
Relies on the client keeping `E` synced to the backend's reported horizon
and clearing it on not_subscribed (E does not self-age); communicated
separately to the clients.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(PFS) pro_backend: throw on parse errors instead of an error vector
(PFS) user_profile: fetch a proof when entitled but holding none
Forward-port of #120 (dev commit b63b4b0) onto pfs; applies unmodified. GetProRevocationsCResponse / GetPaymentDetailsCResponse are aggregates built by the *_parse functions via std::make_unique from a parsed base response. make_unique initializes with parentheses, which only aggregate-initializes under P0960R3 (C++20): GCC implements it, the Apple Clang on the macOS CI runners does not, so it looks for a constructor and finds none. Give each an explicit base-slice constructor; call sites are unchanged. pfs has the same structs and the same make_unique call sites, so it has the same latent macOS break.
Forward-port of #114 (dev commit 89c6acb) onto pfs. Most of #114 is already here: the byte refactor (7662405) had independently given the binary API fixed-extent spans, so sign/verify/pubkey already reject wrong sizes at compile time, the string overloads already validate, and the blinding / group-keys call sites already pass sized views. Two things were missing. First, pfs's verify(string_view) returned false for a wrong-sized signature or pubkey where #114 throws std::invalid_argument, so it conflated "you passed a malformed argument" with "this signature does not verify". Align with dev: letting pfs keep return-false would silently revert #114's behaviour when pfs eventually lands on dev. Nothing in the tree calls the string overloads -- every call site uses the span overloads -- and the return-false came in incidentally with 7662405 rather than as a considered choice. Second, port #114's regression test for the rejected sizes. The three string overloads all validated a length and then narrowed to a fixed span; that is now one require_bytes<N> helper, which also gives the arguments #114's exception wording.
Records dev up to 2b27d27 as merged, keeping pfs's tree unchanged (-s ours). All four PRs in the range are now applied to pfs: - #116 (this-is-not-c) via #115 this-is-not-c-pfs - #118 (renewal-target-no-proof-fetch) via #119 renewal-target-no-proof-fetch-pfs - #120 (macOS C response holders) forward-ported in e682e6b - #114 (fixed-size XEd25519 spans) forward-ported in b03709d Verified for the two that were already applied: #119's user_profile.cpp change is line-identical to #118's, and for #116/#115 the `errs` error-vector is gone from both branches with identical parse_error usage.
Clients sometimes need to know whether a Pro subscription is terminal or auto-renewing (e.g. "renews on X" vs "expires on X"). Store the backend's `auto_renewing` (from get_pro_status) as a presence-only config flag `A`: 1 when auto-renewing, absent otherwise (terminal / unknown / not Pro). Deliberately not tri-state: unlike blinded_msgreqs `M`, this is backend- derived fact, not a defaulted client preference, so there's no upgrade- default edge case that a distinct "unset" would guard. And no t/T bump -- it's synced pro state like E/I/R, not a user-initiated profile edit. Exposes get_/set_pro_auto_renewing (C++ bool; C 0/1) with unit + C-API coverage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
encrypt_device_data() had no caller, so no group was ever visible to another device. The seqno comes back with the bytes because the message is built from a snapshot: confirming the push against a seqno read afterwards would mark clean a change that went out in no message.
A retrieve is capped, so one round need not exhaust a namespace, but "more" was never read and is_final was hardcoded true: a truncated batch was announced as complete and handlers fired on a partial view. Rounds continue against the same node, since the cursor is stored per (namespace, node). An empty batch is now dispatched too. A namespace that answered with nothing is telling us something -- it is what lets a handler know a fetch happened -- while one that failed still reports nothing at all. Configs opt out: there is no state there an empty poll settles.
Without one it lands in Unknown with a free-form string, which every other client then shows as an unrecognised device. The two decoders had the mapping written out twice and a fourth value would have made that three places disagreeing; they now share the inverse of encoded_type().
The four payload-carrying handlers took a const reference to a value Client had read for that one delivery and destroys straight afterwards, so every handler that kept what it was given -- which is what this header asks them to do -- copied it, strings and attachment vector included. Passing it by value and moving out of the emit job removes that copy rather than relocating it: nothing else holds the value, and each job runs exactly once. _emit_lists_replaced was paying the same cost from the other side. Its lambda was not mutable, so handing the captures to the by-value list handlers copy-constructed both vectors on every replacement. A handler written against the old signature still compiles, since a callable taking a const reference binds to a by-value std::function parameter, so existing callers see one fewer copy rather than a change they have to make. Only code naming the std::function types themselves needs touching.
A by-value parameter on the std::function forces a T into existence in operator()'s frame before the handler is reached, so a handler that only reads still pays for one; and it lets a call site omit the move and copy silently, which is what this was meant to stop. An rvalue reference costs nothing for a const&-taking handler, still permits a by-value one, and makes a missing move a compile error. The Core device handlers get the same treatment, which is why the dispatch loop stops being const. Handlers that borrow keep const& -- message_decrypt_failed's argument is one of the caller's own elements, identifiable by pointer, and configs_changed's span is a view.
Four of the six take an id nobody else keeps: the _emit job that carries it runs once and calls one handler. ConversationId holds a std::string of 33 raw bytes for a dm or group, past the small-string threshold, so each of those was an allocation a handler could not avoid. The two progress handlers keep const&: they report repeatedly against one captured id, so a handler that moved from it would empty what the next report needs.
It has not compiled since send_message collapsed into OutgoingMessage and the synchronous message() grew its wait_t; testLive is outside testAll, so only a full build says so.
The lint pipeline has been failing on client for a while, on code that predates any one branch. This is `./utils/format.sh` and nothing else: no include was added or removed, and outside the reordering clang-format's SortIncludes does, not a token changed. jsonnetfmt leaves .drone.jsonnet alone already.
The elements of a braced-init-list are evaluated in order, so testing `it->second` in the second element was testing a moved-from Info. It gave the right answer only because `state` is an enum and a member-wise move leaves scalars intact, so it would have started lying the moment that field gained a destructive move.
set_poll_interval assigned _poll_interval, stopped the ticker and built a new one on the caller's thread, while the loop that owns both ran. Creating or stopping a libevent event off the loop races it -- libquic's own call_later goes out of its way to avoid exactly that -- so the doc's "safe to call at any time" was true only for a caller that happened to call before a network was attached. Marshalled through Loop::call, which runs inline when already on the loop, and the ticker rebuild handed to _update_polling rather than written out a second time. Documents what the interval trades away, and that nothing serialises polls: an interval short enough to overlap gets duplicate requests, which is wasteful but not incorrect.
Two comments described a Client that no longer exists. The constructor's said core::callbacks could be passed and would be forwarded "as for a bare Core", which the static_assert below it forbids outright. An application cannot supply any, so a Core event with no client::callbacks equivalent is a gap to fill here rather than something a caller can reach past Client for. The accessors' said reading off-thread "deadlocks rather than merely racing". It does not: the pool hands each thread its own connection and WAL lets a reader run beside the loop's writer. The reasons to go through the loop are cost and consistency -- a second encrypted connection per reading thread, contention for the single write lock, and a snapshot with no defined relationship to the callbacks already delivered -- so say those instead of a hazard that sends a reader hunting for a deadlock that cannot happen.
last_message was a std::string, so a row could not tell "no messages" from "the latest carries only attachments" -- both arrived empty, and a conversation that had just moved to the top of the list appeared to say nothing. Replaced by an optional MessagePreview: unset means there is nothing to preview, so an empty body on one that is set means the message has no text. Body and attachment count are independent fields rather than alternatives, because a message can carry both and a row wants both halves -- which is why there is no kind enum to switch on. Attachments are summarised to a count plus whether they are a voice message and whether they are all images: enough vocabulary for a row, without the filenames and content types that are a message view's business. Costs two queries for a list of any size: the body and sender come from a join on one index seek per conversation, and the attachment aggregate is batched over every previewed message at once, as a page of history already does.
A device's state never goes on the wire -- it is inferred from which message the record arrived in -- so a state change moves no field that the record's seqno versions. upsert_device_info guarded on `excluded.seqno > seqno`, which therefore discarded exactly the transitions it was there to decide: an applicant is stored Pending at seqno 1, the accepting device pushes the identical record as Registered at seqno 1, every device compares 1 > 1 and stays Pending. Registration could not complete. State values are renumbered least to most authoritative so the stored integer is a rank, and the guard compares (state, seqno) as a row value. That subsumes the special cases: equal rank falls back to the seqno, an acceptance outranks a newer link request, and a kick outranks everything. Rank only increases and the order is total, so a merged result is the maximum over everything received regardless of arrival order. Kicked becomes a state of its own rather than a second job for Unregistered, which had been covering both "removed from the group" and "never in it" -- two answers that the merge and the payload writer each had to separate by a different ad-hoc test. A schema CHECK ties it to kicked_timestamp so the coupling is enforced rather than remembered, and the ungated kick update becomes an upsert: an update alone matched nothing for a device that joined after the removal, silently storing no tombstone and leaving that device free to accept the removed one back. Also drops kicked_timestamp from upsert_device_info, where it only ever wrote the NULL it was inserted with; the rank guard is now what keeps a record from overwriting a tombstone. No migration: these tables have no rows anywhere yet.
Picks up session-sqlite's bind_each, which is what a runtime-sized parameter list needs to go through bind_oneshot at all, and covers it with tests here since session-sqlite has no suite of its own. The tests that matter are the composing ones: a sequence between two ordinary values, and two sequences in one call. A single sequence on its own passes whether or not the parameter counter advances correctly, so it cannot tell a working implementation from one that numbers parameters by argument position.
A row saying "invoice.pdf" is worth considerably more than one saying "1 file", and the count comes along for free as the vector's length. One entry per attachment, in the order the sender listed them, so the entries line up with Attachment::index and the length is an exact count. An entry is empty where the sender omitted the name, which it may: the names cannot stand in for the attachments, and a row needs a fallback for the empty ones. The query becomes a row per attachment rather than an aggregate, since the names are wanted individually; the three summary fields are folded from those same rows instead of being asked for separately.
Three build fixes merged into the two dependency repositories, and this is
what brings them in.
session-deps (dbda1a9a..30b20092):
- libevent is built --with-pic, so its archive can be linked into a shared
object. Without it an x86-64 link fails with a R_X86_64_PC32 relocation
against event_base_loop.
- CMake-based dependencies are configured with the cross toolchain file
rather than the compiler binary alone. A cross compiler invoked without
its target builds for the host, and the archive links against the wrong
platform's standard library - on Android, libstdc++ symbols that are not
there.
- session_deps_version 1.7 -> 1.8, which is session-deps' own major-version
compatibility marker; the major is unchanged.
session-router (2e0b7dbb..054d3b9f):
- target_architecture() recognises arm64 on macOS instead of calling
FATAL_ERROR on it, so configuring for Apple silicon works.
All three were carried as out-of-tree patches by a consumer until now.
Nothing here changes what libsession-util builds; the .gitmodules URLs are
unchanged and both commits are on their repository's dev branch.
Bump session-deps and session-router for the cross-build fixes
Every client draws a path screen naming the country of each hop, and each of them currently ships and maintains its own geo database to do it. This puts the lookup upstream: session::ip_country::lookup(ipv4) returns an ISO 3166-1 alpha-2 code, with available(), attribution() and database_version() alongside it. It is off by default. With WITH_IP_GEOLOCATION off the compiled-in database is an empty one rather than absent, so every lookup misses and a client needs no #ifdef of its own; available() is a link-time fact, not a macro, so nothing about the option reaches a header. data.cpp and no_data.cpp define the same accessors and the lookup itself is identical either way -- only the table it searches differs. DB-IP Lite is the source, chosen over MaxMind's GeoLite2 on licensing rather than accuracy: CC BY 4.0 permits redistribution and has no clause requiring a copy to stay current, which is what makes a bundled snapshot viable at all. Its IPv4 rows already tile the address space with no gaps and no mergeable neighbours, so a range needs only its first address -- the next range's start ends it. That leaves parallel arrays of 357k ipv4 starts and uint8_t country indices plus a 246-entry code table: 5 bytes a range, 1.79MB, of which a binary search touches only the 1.43MB of starts. The codes are numbered by descending range count. The countries holding the most ranges get the shortest indices, which is worth ~0.4MB of generated source, and the rare countries -- the ones that come and go between releases -- land at the end where nothing follows them to renumber. Numbering them alphabetically instead rewrote 86% of the table across the Aug->Sep refresh, where two mid-alphabet countries disappeared; this ordering rewrote 9%. The generated table is not committed: utils/update-ip-country-db.py downloads a release and generates it, and cmake refuses to configure with the option on until it has been run. Nothing downloads during a build. The tests run in both configurations and check the mechanism -- table invariants, range boundaries, the unknown path -- rather than pinning countries, save for one anchor commented as expected to move when the snapshot does.
POSIX declares `::wait` in <sys/wait.h>, so a translation unit that does
`using namespace session::client;` and pulls in that header -- which
macOS and glibc both make easy -- finds two `wait`s and can use neither:
error: reference to 'wait' is ambiguous
note: candidate found by name lookup is 'wait'
note: candidate found by name lookup is 'session::client::wait'
There is no fix for that at namespace scope. A using-declaration next to
the using-directive is rejected outright ("target of using declaration
conflicts with declaration already in scope"), and a using-directive in an
inner namespace does not help, since it injects the name into the nearest
namespace enclosing both -- the global one, where `::wait` already is.
What is left is a block-scope using-declaration in every function that
wants it, or qualifying every call site, and neither is something to ask
of a client.
So the tag becomes `block_t`/`block`, and its doc block says why, so that
the next reader does not rename it back. The reason it is not a variable
problem in the first place is that `wait` is an object: a function of that
name would merge into an overload set with `::wait(int*)` and resolve by
arity.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rename the blocking-call tag from `wait` to `block`
Add an optional IP-to-country lookup behind a cmake option
`client` branched off `pfs` and was meant to sit on top of it, but the two ran side by side for a month: 192 commits here, 38 there. This closes that, and `pfs` is retired -- future work happens on `client`. It also fixes CI. The Pro backend dropped `"version": 0` from the proof response on 2026-08-17 (session-pro-backend 2ce104a), and PR #130 answered it the same day by deleting the field outright -- a proof's format is fixed by the endpoint that issued it and bound into `sig` by the domain prefix, so the only party that has to discover a version is an offline peer, which reads it from the protobuf envelope. That went to `dev` and to `pfs` (PR #131) and never reached `client`, whose [pro_live] job has been failing on `Key 'version' is missing` ever since. Three resolutions needed a decision rather than a pick: - generate_download_url: `client` gave it a `stream_encrypted` parameter and `sr=` fragments; `pfs` gave it the port suffix. Both are wanted, so the signature is client's and the port handling pfs's. The url tests move to the port-bearing expectations, since `example.com:123` on http states a port now. - proto/debug_print.cpp exists only on `client`, so it merged untouched while the schema under it lost `ProProof.version`. Its print block goes; an old proof still carrying field 1 falls to `unknown_fields`, which that function already prints. - "Configs: what a skipped seqno costs afterwards" pinned the spurious seqno increment as observed behaviour, and ba569b2 fixes it -- as the test's own closing note anticipated. Rewritten to assert what now holds: the duplicate is adopted at its own seqno, so the peer's next change lands cleanly and owes no conflict push. testAll: 392 cases pass. [pro_live] against session-pro-backend dev: 3 cases, 100 assertions, all pass.
Forward-port of dev commit fea5acc; line-for-line identical to dev's, as client's pipeline list still had Static iOS in the position dev moved it from.
First dev->client marker merge, replacing the dev->pfs ones now that pfs is retired. 61f9529 brought all of pfs into client, so dev was already recorded merged through cd2aca9 and only #139 remained. Records dev up to 1d565e3 as merged, keeping client's tree unchanged (-s ours): - #139's url fix (24bd95c) forward-ported in 6aa2608. - fea5acc (CI: run static iOS first) forward-ported in a8805d8. 24bd95c's other half bumps 1.9.0 -> 1.9.1 and is deliberately not taken: dev carries the 1.x line, client the in-development 2.x, so dev's version bumps are never applied here.
`block` already means something else in this library: `set_blocked(bool blocked, block_t)` had one word doing two unrelated jobs in a single declaration. `await` is free of both hazards the name has to clear -- it is not a keyword (`co_await` is), and nothing libc or POSIX declares at global scope shadows it, so it survives a `using namespace session::client;` in application code the way `wait` would not.
Rename the blocking-call tag to `await`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This draft PR tracks the full client support being developed in libsession, to serve as the logic core of future versions of Session. This builds on top of PFS+PQ support (PR #103), and adds a ton of new features and capabilities needed to build a full Session client. The most notable starting point here is the
Clientclass which is the entry point for an active programmable Session client.This branch is not intended for review, but rather merely tracks the progress of the ongoing
clientbranch (which will eventually become thedevbranch).