shsp 1.11.1
shsp: ^1.11.1 copied to clipboard
Single HandShake Protocol (SHSP) - a custom networking protocol for peer-to-peer communication. Unified package containing types, interfaces, and implementations.
Changelog #
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
1.11.0 - 2026-08-09 #
Added #
src/config/shsp_config.dart:config_manager-backed configuration surface —initShspConfig(),shspConfigSector,defaultShspConfigandShspConfigExtension(defaultKeepAliveSeconds,defaultHandshakeTimeoutMs,defaultHandshakeIntervalMs,defaultRetryMaxAttempts,defaultRetryInitialDelayMs,defaultRetryBackoffMultiplier), replacing hardcoded defaults with overridable, deep-mergeable settingsmain_injection.dart(moved tosrc/): generatedMainInjectionShspMixin/MainInjectionShspwithregisterAllSingletonsShsp()/registerAllSingletonsShspAsync()and before/after hooks, wiring every@dependencyInjectableSHSP class intoRegistryManagersrc/impl/registry/dual_shsp_registry_wiring.dart:connectDualShspSockets()(binds IPv4/IPv6RawDatagramSockets best-effort, registering whichever succeeded under the'ipv4'/'ipv6'subkeys, and throwingSocketExceptiononly if neither could be bound),connectShspSocketMigratableSubkeys(),connectAutoShspPeerSubkeys(),connectAutoShspInstanceSubkeys(), andDualShspInjectorwiring all of the above into the DI before-register hookssrc/impl/migration/shsp_socket_migration.dart/dual_shsp_socket_migration.dart:migrateShspSocket(),migrateShspSocketIpv4(),migrateShspSocketIpv6()andmigrateDualShspSockets(), swapping the registeredRawDatagramSocket/IShspSocketfor a subkey/family while carrying the previous socket's profile over to the new one, without replacing the liveIShspSocketMigratable/IDualShspSocketMigratablerouterIDualShspSocket.getSocket([InternetAddressType])/DualShspSocket.getSocket(): unified accessor for the IPv4/IPv6 socket, replacing directipv4Socket/ipv6Socketfield access in handshake and registry codeRegistryShspSocket,DualShspSocketAuto,DualShspSocketMigratableand related classes are now@dependencyInjectable, with generateddependencyInjectionFactory()constructors resolving optional dependencies viaRegistryManager.tryGetInstance()DualShspSocketAutois now@dependencyInjectabledirectly: its unnamed constructor takesipv4Migratable/ipv6Migratable(resolved via@Subkey('ipv4')/@Subkey('ipv6')), and the previousSockets-based unnamed constructor is nowDualShspSocketAuto.fromSockets(...)DualShspSocketMigratableis now@dependencyInjectabledirectly, mirroringDualShspSocketAuto: its unnamed constructor takesipv4Migratable/ipv6Migratable, and the previous.fromMigratables(...)named constructor is merged into it; the oldSockets-based unnamed constructor is nowDualShspSocketMigratable.fromSockets(...)
Changed #
RegistryManager(generic keyed registry,registry_utility.dart) renamed toKeyedRegistry/KeyedRegistryManager/KeyedRegistrySingleton, dropped itsIValueForRegistrytype bound, and now supports arbitraryValuetypesRegistryShspSocketswitched fromRegistrytoKeyedRegistry, gained an optional-socket constructor and adestroy()that iterates registered sockets directly instead of delegating to the removedRegistry.destroyAll()- Renamed
ShspSocketWrapper→ShspSocketMigratableandIShspSocketWrapper→IShspSocketMigratable(withShspSocketWrapperDelegationMixin→ShspSocketMigratableDelegationMixin) so the single-socket and dual-socket migration types share the same naming (ShspSocketMigratable/DualShspSocketMigratable) - Renamed the associated members for the same reason:
getSocketWrapper()→getSocketMigratable(),ipv4SocketWrapper/ipv6SocketWrapper→ipv4SocketMigratable/ipv6SocketMigratable, and theipv4Wrapper/ipv6Wrapperparameters →ipv4Migratable/ipv6Migratable i_shsp_socket_wrapper.dartmoved fromsrc/interfaces/wrapper/tosrc/interfaces/socket/i_shsp_socket_migratable.dart, alongsidei_shsp_socket.dart/i_shsp_socket_base.dartmain_injection.dartnow registersIDualShspSocketAuto → DualShspSocketAutoandIDualShspSocketMigratable → DualShspSocketMigratableinstead ofIDualShspSocketWrapper → DualShspSocketWrapper, completing the DI tree:RawDatagramSocket→IShspSocket→IShspSocketMigratable→ bothIDualShspSocketAutoandIDualShspSocketMigratableresolve independently from the same ipv4/ipv6 instancesRegistryShspSocket.initialize()/bind()updated to usegetSocket()andShspSocketMigratable/DualShspSocketMigratableinstead of the removed wrapper types;initializeDI()removed- Generated DI factories (
AutoShspInstance,AutoShspPeer,RegistryShspSocket,ShspSocket,DualShspSocketAuto,DualShspSocketMigratable) resolve optional dependencies viaRegistryManager.tryGetInstance()instead of the removedgetInstanceNullable(), following thesingleton_manager/singleton_manager_generatorbump to^2.2.2/^2.3.2
Removed #
handshake_ip.dart,IHandshakeIPand thestunpackage dependency — STUN-based public/local IP discovery dropped entirely, including its testsinitialize_point.dartand its examples/tests (initializePointDualShsp,initializePointRegistryAccess) — superseded bymain_injection.dart+dual_shsp_registry_wiring.dartDualShspSocketWrapper,IDualShspSocketWrapper,DualShspSocketWrapperDelegationMixin— merged intoDualShspSocketAuto, which now owns its own DI resolution instead of being wrapped by a delegating facadeRegistrySingletonShspSocket.initializeDI()
1.10.1 - 2026-07-15 #
Fixed #
AutoShspPeer.close()never unregistered its socket-changed listener fromShspSocketSingleton, leaking the callback registration after the peer was closed
Added #
- New public mixins, exported from the
package:shsp/shsp.dartbarrel:IdempotentCloseMixin: idempotentclose()/destroy()with anisClosedflag and acloseImpl()hookMessageSizeValidationMixin: shared outgoing-message validation (closed state, empty payload, max UDP size)SocketChangeListenerMixin: registration/deregistration of a singleton socket-changed listener that re-registers the message callback on the new socketSocketProfileTransferMixin: profile extract/close/rebuild/apply/notify sequence for socket replacement (transferProfileAsync/transferProfileSync)ShspSocketWrapperDelegationMixin/DualShspSocketWrapperDelegationMixin: member-by-member delegation to the wrapped socket
Changed #
ShspPeer,ShspSocket,ShspSocketWrapper,DualShspSocketWrapper,BaseShspSocketSingleton,AutoShspPeerandAutoShspInstancerefactored to use the new mixins instead of duplicated inline logic (no behavioral change besides the fix above)
1.10.0 - 2026-07-13 #
Added #
DualShspSocketAuto.fromMigratable()constructor to build an auto-refreshing dual socket from an existingDualShspSocketMigratableIDualShspSocketMigratable.ipv4SocketWrapper/ipv6SocketWrappergetters, throwingStateErrorwhen the underlying socket isn't wrapped
Changed #
ShspSocket.bindDefault()now defaultsipv6totrue(previouslyfalse)buildDualSocket()(used byinitializePointDualShsp()andinitializePointRegistryAccess()) now returnsIDualShspSocketAuto, built viaDualShspSocketAuto.create(), instead of manually wiringDualShspSocketMigratableinitializePointDualShsp()andinitializePointRegistryAccess()now also register the socket underIDualShspSocketAuto, in addition to the existingIDualShspSocketMigratableregistrationDualShspSocketWrapperDInow resolvesIDualShspSocketAutofrom DI instead ofIDualShspSocketMigratableIDualShspSocketWrapper.internalSocketnow typed asIDualShspSocketAuto(previouslyIDualShspSocketMigratable)- Socket wrapper files reorganized:
src/impl/socket/wrappers/merged intosrc/impl/socket/core/shsp_socket_wrapper.dartandsrc/impl/socket/dual/dual_shsp_socket_wrapper.dart
Fixed #
- Copy-paste bug in
DualShspSocketAuto.fromMigratable()that assigned the IPv4 wrapper to both the IPv4 and IPv6 slots DualShspSocketWrapperandSocketswere missing from thepackage:shsp/shsp.dartbarrel export after thewrappers/→core/+dual/file move; regenerated viaindex_generatorAddressUtility.parseAddress()test expectation andgetLocalIp()/canCreateIPv6Socket()call sites updated to match theirFuture-returning signatures
Test Coverage #
- Added
fromMigratabletest group (dual_shsp_socket_auto_test.dart) asserting IPv4/IPv6 wrappers are distinct instances, covering the previously-untested constructor where the copy-paste bug above was hiding - Added
dual_shsp_socket_wrapper_test.dart: full coverage forDualShspSocketWrapper's three constructors (default,emptyForDI,createFromSocket) and every delegated member, with IPv4/IPv6 pairs asserted as distinct instances to catch swap-style bugs
1.9.0 - 2026-07-12 #
Added #
DualShspSocket as IShspSocket
IDualShspSocketno longer extendsIShspSocket— it is now a pure router interface extendingIShspSocketBaseIShspSocketBaseextracted fromIShspSocketproviding core members (onClose, onError, onListening, setMessageCallback, sendTo, isClosed, destroy) without theRawDatagramSocketcontractIDualShspSocketAutointerface for auto-detecting and refreshing dual-stack socket instances
Optional IPv4/IPv6
- IPv4 socket is now optional in
DualShspSocket— the framework works with IPv6-only or IPv4-only setups DualShspSocket.create()attempts IPv6 first, then IPv4, and works if at least one succeedssocketgetter returns IPv6 socket with IPv4 fallbacklocalAddress,localPort,compressionCodecall prefer IPv6 with IPv4 fallback
Auto-Detection via DualShspSocketAuto
DualShspSocketAutoautomatically refreshes underlying sockets to handle network changesrefreshSocketIpv4(),refreshSocketIpv6(),refreshSockets()methods for on-demand socket refresh- Implements
IDualShspSocketMigratablefor seamless socket migration
New Types
Socketsvalue object holding optional IPv4 and IPv6IShspSocketreferences- Centralized in
src/types/sockets.dart - Used throughout
DualShspSocket,DualShspSocketMigratable, andDualShspSocketWrapperconstructors
Enhanced Callback Types
CallbackOnWithSocketandCallbackOnErrorWithSocket— callbacks now carry the source socket reference inDualShspSocketevents- Event handlers can identify which socket (IPv4 vs IPv6) triggered the event
Changed #
Interface Reorganization
IShspSocketmoved tosrc/interfaces/socket/i_shsp_socket.dartIDualShspSocketmoved tosrc/interfaces/dual/i_dual_shsp_socket.dartIDualShspSocketMigratablemoved tosrc/interfaces/dual/i_dual_shsp_socket_migratable.dartIDualShspSocketAutoadded tosrc/interfaces/dual/i_dual_shsp_socket_auto.dartIShspSocketBaseadded tosrc/interfaces/socket/i_shsp_socket_base.dart
DualShspSocket Constructor Change (Breaking)
- Constructor now accepts
Sockets socketsinstead of(IShspSocket ipv4Socket, IShspSocket? ipv6Socket) fromSocketsfactory now takesSocketsinstead of two parameters
IPv4/IPv6 Preference Changes
localAddressreturns IPv6 address first (previously IPv4 first)localPortreturns IPv6 port first (previously IPv4 first)compressionCodecprefers IPv6 codec (previously IPv4 first)isCloseduses AND logic (both must be closed) instead of OR
ISendTo Validation
sendTo()validates address family matches available socket type- Throws
StateErrorwhen sending IPv6 address with only IPv4 socket (and vice versa)
Fixed #
Bug Fixes
- Handshake IP mapping race condition resolved
- Socket callback forwarding in dual socket properly identifies source socket
- Message callback map IPv4/IPv6 key parity fixed
- Various constructor consistency improvements across factories
Test Coverage #
- 1,589+ comprehensive test lines added for dual socket scenarios:
dual_shsp_socket_comprehensive_test.dart: 1,286 lines covering IPv4-only, IPv6-only, dual-stack, and migration scenariosdual_shsp_socket_auto_test.dart: 303 lines testing auto-detection and socket refresh
1.8.0 - 2026-04-20 #
Added #
Test Coverage
- 10 comprehensive test files with 227+ test cases covering all SHSP components:
shsp_exceptions_test.dart: All 6 exception types (ShspProtocolException, ShspNetworkException, ShspValidationException, ShspHandshakeException, ShspInstanceException, ShspConfigurationException)peer_types_test.dart: PeerInfo/RemoteInfo with JSON round-trips, equality, and hashCodeaddress_utility_test.dart: AddressUtility static methods (format, parse, fromString, getLocalIp, canCreateIPv6Socket)callback_map_test.dart: Generic CallbackMapcompression_codecs_test.dart: All 3 compression codecs (GZipCodec, ZstdCodec, LZ4Codec)keep_alive_timer_test.dart: KeepAliveTimer lifecycle (periodic, from, cancel, resetTick)shsp_socket_test.dart: ShspSocket operations (bind, fromRaw, close, sendTo, profile round-trips)dual_shsp_socket_test.dart: DualShspSocket and SimpleDualSocketSingletonshsp_peer_test.dart: ShspPeer construction, validation, delivery, and lifecycleshsp_instance_test.dart: ShspInstance message routing (0x00-0x04 prefixes) and state machineshsp_handlers_and_factories_test.dart: ShspHandshakeHandler, ShspInstanceHandler, and all Factory classes
Coverage includes: exceptions, types, utilities, callbacks, sockets (single/dual), peers, instances, handlers, factories, and compression.
Test patterns: Manual mocks (no mockito), Future.microtask() for callbacks, Future.delayed() for timers, real UDP sockets on loopback, full internal src/ imports enabled.
Changed #
- Documentation now aligns with comprehensive test coverage
- Quality baseline established with 227 test cases passing
Result: ✅ Comprehensive test suite - All major components verified
1.7.1 - 2026-04-11 #
Fixed #
Code Quality
- Removed unused import
dart:typed_datafrom peer_communicator.dart - Removed unused variable
startTimefrom test file - Added
constkeyword to all constructors for performance optimization - Fixed double literal
2.0to2where appropriate - Optimized
constdeclarations in test code
Result: ✅ Zero dart analyze issues - Ready for pub.dev maximum score
1.7.0 - 2026-03-30 #
Added #
IDualShspSocketWrapperinterface forDualShspSocketWrapper/DualShspSocketWrapperDIproxyIRegistryShspSocketinterface forRegistryShspSocket
Changed #
buildDualSocket()now returnsIDualShspSocketMigratableinstead ofDualShspSocketMigratableinitializePointDualShsp()registers registry underIRegistryShspSocketinterfaceinitializePointRegistryAccess()usesIDualShspSocketWrapperandIRegistryShspSocketas registration keysDualShspSocketWrappernow explicitly implementsIDualShspSocketWrapperRegistryShspSocketnow explicitly implementsIRegistryShspSocketShspHandshakeHandler.handshakeInstancerewritten as event-driven (Completer + Timer.periodic) instead of polling; eliminates a race condition where theonOpencallback was never invoked when the socket read event and the delay timer fired in the same event-loop tick
1.6.0 - 2026-03-26 #
Changed #
- Updated
singleton_managerdependency from^0.4.0to^0.5.0 - Updated
singleton_manager_generatordev dependency from^1.0.4to^1.2.0 - Renamed
isClosing()toisClosingMessage()inShspInstanceHandshakeMixin - Renamed
isClosed()toisClosedMessage()inShspInstanceHandshakeMixin
Removed #
- Removed
archivedependency
1.5.0 - 2026-03-20 #
Changed #
IDualShspSocketMigratableis now the primary DI type replacingIDualShspSocketthroughout the frameworkinitializePointDualShsp()now creates aDualShspSocketMigratable(instead ofDualShspSocket) and registers it underIDualShspSocketMigratableDualShspSocketWrapper.dualSocketandinternalSocketsetter are now typedIDualShspSocketMigratableISimpleDualSocketSingleton.getInstance()/setInstance()now useIDualShspSocketMigratableRegistryShspSocket.initialize()now acceptsIDualShspSocketMigratable;bind()createsDualShspSocketMigratableinternallyRegistryShspSocket.initializeDI()resolvesIDualShspSocketMigratablefrom DI
Breaking Changes #
SingletonDIAccess.get<IDualShspSocket>()is no longer registered byinitializePointDualShsp()— useget<IDualShspSocketMigratable>()insteadISimpleDualSocketSingleton.setInstance()now requires anIDualShspSocketMigratable; plainIDualShspSocketinstances are no longer accepted
1.4.0 - 2026-03-20 #
Added #
IShspSocketWrapperinterface: New contract for socket proxy/wrapper classesmigrateSocket(IShspSocket newSocket)— swaps the underlying socket and re-applies stored callbacks
IDualShspSocketMigratableinterface: Contract for dual-socket migrationmigrateSocketIpv4(IShspSocket socket)— replaces the IPv4 underlying socketmigrateSocketIpv6(IShspSocket socket)— replaces or adds the IPv6 underlying socket
DualShspSocketMigratable: New class extendingDualShspSocketthat implementsIDualShspSocketMigratable- Wraps raw sockets in
ShspSocketWrapperautomatically via its default constructor fromWrappersnamed constructor for pre-wrapped socket injection- Enables live socket migration without losing peer callbacks or references
- Wraps raw sockets in
Changed #
ShspSocketWrappernow implementsIShspSocketWrapperinstead of bareIShspSocket- Added anti-nesting guard: wrapping another
ShspSocketWrapperthrowsArgumentError - Stores listening, close, and error callbacks internally so they are re-applied on every
migrateSocket()call
- Added anti-nesting guard: wrapping another
1.3.0 - 2026-03-19 #
Added #
IShspSocketimplementsRawDatagramSocket: The socket interface now extendsRawDatagramSocketdirectly, makingIShspSocketa full drop-in replacement forRawDatagramSocketin any Dart APIShspSocketWrapperprovides complete delegation of allRawDatagramSocketmembers (address,port,send,receive,broadcastEnabled,multicastLoopback,multicastHops,multicastInterface,readEventsEnabled,writeEventsEnabled,joinMulticast,leaveMulticast, etc.)- Added
_rawcomputed getter inShspSocketWrapper— automatically reflects the current underlying socket after any swap
Changed #
IShspSocket: Added explicitdestroy()method to the interface contractIDualShspSocket: Removed redundantsocketgetter —RawDatagramSocketaccess is now inherited throughIShspSocketDualShspSocketWrapper: Removedsocketoverride for the same reason- Removed redundant imports in
dual_shsp_socket.dartandinitialize_point.dart
Breaking Changes #
- Any class implementing
IShspSocketmust now also implement allRawDatagramSocketmembers
1.2.4 - 2026-03-19 #
Fixed #
- Incomplete
shsp.dartbarrel: Regenerated root library with all missing exports- Added factory interfaces:
i_shsp_instance_factory,i_shsp_peer_factory,i_shsp_socket_factory - Added utility interfaces:
i_address_utility,i_callback_map,i_keep_alive_timer,i_message_callback_map,i_message_callback_map_singleton,i_raw_shsp_socket,i_shsp_socket_info_singleton - Added socket features:
shsp_socket_callbacks,shsp_socket_compression,shsp_socket_profile - Added dual socket:
dual_shsp_socket_message,dual_shsp_socket_profile - Reorganized exports in alphabetical/logical order
- Added factory interfaces:
1.2.3 - 2026-03-19 #
Fixed #
- Missing Index Export: Added
i_shsp_socket_base.darttosrc/interfaces/index.dart- The interface was accessible via the root
shsp.dartbut missing from the sub-index barrel
- The interface was accessible via the root
1.2.2 - 2026-03-19 #
Fixed #
- Analyzer Issues: Resolved all Dart analyzer warnings and errors
- Removed unused local variables
- Added missing test dependencies (
singleton_manager) - Updated deprecated callback setters to use new
CallbackHandler.register()patternsetListeningCallback()→onListening.register((_) {})setCloseCallback()→onClose.register((_) {})setErrorCallback()→onError.register((_) {})
1.2.1 - 2026-03-14 #
Added #
- Initialize Point Function: New
initializePointDualShsp()function for convenient singleton setup- Automatically initializes IPv4 and IPv6 sockets
- Handles IPv6 availability detection
- Sets up dual socket and registry singleton
- Socket Wrapper: New
ShspSocketWrapperclass for transparent socket replacement- Implements proxy pattern to allow underlying socket swapping
- Maintains stable references while supporting socket migration
- Enables graceful socket reconnection and state transfer
Changed #
- Improved singleton initialization pattern with dedicated entry point
- Registry initialization now integrated into centralized initialization flow
1.2.0 - 2026-03-11 #
Added #
- Registry System: New generic registry pattern with mixin-based API for managing multiple instances:
Registry<Key, Value>mixin for key-value based instance managementSingletonclass for type-based instance managementIValueForRegistryinterface for registry-managed objectsRegistryMixintrait for registering and managing sockets/peers
- Extended Interface Support: Socket and peer interfaces now support registry integration:
IShspSocketimplementsIValueForRegistrywithdestroy()methodIShspPeerimplementsIValueForRegistrywith proper cleanup
- Socket Type Enumeration: New
SocketTypeenum for IPv4/IPv6 socket management - Registry Utilities: Helper functions for socket registry initialization and management
Changed #
- Registry Version Preservation: Registry now preserves element version during updates instead of incrementing
register()maintains the existing version when updating an element- New elements are initialized with version 0
- This enables stable version tracking across updates
Fixed #
- Improved resource cleanup with
destroy()methods throughout the API - Better type safety with registry-based instance management
1.0.0 - 2026-03-10 #
Added #
- Initial release of the unified SHSP (Single HandShake Protocol) package
- Core networking protocol implementation for peer-to-peer communication over UDP
ShspSocket: Main UDP socket implementation with callback managementShspPeer: High-level peer abstraction for bidirectional communicationShspInstance: Protocol instance with automatic keep-alive supportShspSocketSingleton: Global socket management with state transfer and reconnection supportAutoShspPeer: Auto-wiring peer that binds toShspSocketSingletonwith automatic reconnectionAutoShspInstance: Auto-wiring instance with automatic socket management- Compression support with three pluggable codecs:
GZipCodec: Best compression ratioLZ4Codec: Fast compression with reasonable ratiosZstdCodec: Balanced compression and speed
- Comprehensive type definitions:
RemoteInfo: Address and port informationSocketProfile: Socket configuration and state trackingInstanceProfile: Instance configuration and state tracking- Callback type definitions for various protocol events
- IPv4 and IPv6 support with automatic address formatting
- Dual-stack socket support for seamless IPv4/IPv6 interoperability
CallbackMapandMessageCallbackMaputilities for managing callbacksAddressUtilityfor address formatting- Complete interface contracts for extensibility
- 399+ comprehensive tests ensuring reliability
- Multi-platform support (Dart CLI, Flutter mobile, web)
- Comprehensive documentation and examples
- GitHub Actions CI/CD pipeline
- LGPL-3.0 license
Features #
- Automatic handshake with configurable timeouts and retry intervals
- Configurable keep-alive heartbeat (default: 30 seconds)
- Non-blocking async/await API throughout
- Singleton pattern for global socket management
- Callback-based message/data reception
- Automatic socket state management and reconnection
- Extensible compression codec interface
- Full type safety with Dart type system