Skip to content

Comments

Feature/unified ethernet#195

Closed
craigmillard86 wants to merge 1 commit intoCarlosDerSeher:developfrom
anabolyc:feature/unified-ethernet
Closed

Feature/unified ethernet#195
craigmillard86 wants to merge 1 commit intoCarlosDerSeher:developfrom
anabolyc:feature/unified-ethernet

Conversation

@craigmillard86
Copy link

This PR consolidates and refactors the network interface components to provide seamless Ethernet/WiFi handover with static IP support. It replaces the separate eth_interface and wifi_interface components with a unified network_interface component that coordinates both interfaces.

Key Features

  • Ethernet/WiFi Failover: Automatic handover between Ethernet and WiFi when connection is lost/restored
  • Ethernet Priority: When both interfaces are available, Ethernet takes priority
  • Deferred Takeover During Playback: Ethernet takeover waits for audio playback to stop to avoid audio glitches
  • Static IP Support: Configure static IP, gateway, netmask, and DNS via web UI
  • DHCP Support: Properly restarts DHCP client on Ethernet reconnect
  • FreeRTOS EventGroups: Replaces volatile bool flags for inter-component communication (thread-safe)

Technical Changes

New Components:

  • components/network_interface/ - Unified network management
    • network_interface.c - EventGroups API for playback state signaling
    • eth_interface.c - Rewritten Ethernet handling with failover logic
    • wifi_interface.c - WiFi interface wrapper

Modified Components:

  • components/lightsnapcast/player.c - Signals playback start/stop via EventGroups
  • main/main.c - Initializes network events, simplified network handling

Removed Components:

  • components/eth_interface/ - Replaced by unified component
  • components/wifi_interface/ - Replaced by unified component

Fixes Included

  • Fix DHCP not restarting on Ethernet reconnect ("invalid static ip" error)
  • Fix race condition causing double-free crash during handover
  • Fix player not restarting after sync failure
  • Skip Ethernet wait when Ethernet is disabled in settings

craigmillard86 added a commit to anabolyc/esp32-snapclient that referenced this pull request Jan 26, 2026
Move internal-only functions out of public header:
- network_get_event_group
- network_request_reconnect
- network_is_playback_active
- network_is_our_netif
- network_events_deinit
- network_if_get_ip

Use extern declarations in eth_interface.c and wifi_interface.c
for functions they need from network_interface.c.

Addresses review feedback on PR CarlosDerSeher#195.
craigmillard86 added a commit to anabolyc/esp32-snapclient that referenced this pull request Jan 26, 2026
Replace extern declarations in eth_interface.c and wifi_interface.c
with a proper private header using ESP-IDF's PRIV_INCLUDE_DIRS CMake
feature. This follows the convention used by improv_wifi component
and addresses PR CarlosDerSeher#195 review feedback.

Changes:
- Create priv_include/network_interface_priv.h with declarations for
  network_get_event_group, network_request_reconnect,
  network_is_playback_active, and network_is_our_netif
- Add PRIV_INCLUDE_DIRS to CMakeLists.txt
- Replace extern declarations with #include in eth_interface.c
- Replace extern declaration with #include in wifi_interface.c
@CarlosDerSeher
Copy link
Owner

So I found some time to test this just now and found a Problem.

  1. start up with ethernet connected and wifi available. No audio from snapserver at all time
  2. disconnect ethernet cable. --> wifi fallback successful
  3. connect cable again --> device reboots
I (30512) ETH_IF: Ethernet disconnected; triggering WiFi fallback
I (30512) ETH_IF: Ethernet Link Down
W (30515) SC: error writing timesync msg
I (30520) SC: Wait for network connection
I (30527) SC: Default netif present but no IP yet: ETH_DEF
I (30531) SC: Reconnect requested: no active netconn (loop start)
I (32058) esp_netif_handlers: sta ip: 192.168.1.103, mask: 255.255.255.0, gw: 192.168.1.2
I (32058) WIFI_IF: Wifi Got IP Address
I (32060) WIFI_IF: ~~~~~~~~~~~
I (32064) WIFI_IF: WIFIIP:192.168.1.103
I (32068) WIFI_IF: WIFIMASK:255.255.255.0
I (32073) WIFI_IF: WIFIGW:192.168.1.2
I (32077) WIFI_IF: ~~~~~~~~~~~
I (32587) SC: WiFi up, waiting for Ethernet (1/5)...
I (33587) SC: WiFi up, waiting for Ethernet (2/5)...
I (34587) SC: WiFi up, waiting for Ethernet (3/5)...
I (35587) SC: WiFi up, waiting for Ethernet (4/5)...
I (36587) SC: WiFi up, waiting for Ethernet (5/5)...
W (37587) SC: Ethernet not available, falling back to WiFi
I (37587) SC: Using WiFi interface
I (37587) SC: Enable mdns
I (37589) SC: Lookup snapcast service on network
I (40608) SC: 
~~~~~~~~~~ MDNS Query success ~~~~~~~~~~
I (40609) NETF: Interface: sta
I (40609) NETF: Type: V4
I (40610) NETF:   PTR : Snapcast
I (40614) NETF:   SRV : openmediavault-2.local:1704
I (40620) NETF:   A   : 192.168.1.16
I (40624) SC: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I (40630) SC: Found 192.168.1.16:1704
I (40634) SC: Binding netconn to interface WIFI_STA_DEF (idx 4)
I (40641) SC: Successfully bound netconn to WIFI_STA_DEF (idx 4)
I (40647) SC: Connecting to remote 192.168.1.16:1704 using local interface WIFI_STA_DEF
I (40915) SC: netconn connected using WIFI_STA_DEF
I (40916) SC: eth mac: xxxxxxxxxxxxxxxxxxxx
I (40916) SC: sta mac: xxxxxxxxxxxxxxxxxx
I (40921) SC: netconn sent hello message
I (40925) SC: Buffer length:  700
I (40927) SC: Latency:        0
I (40931) SC: Mute:           0
I (40935) SC: Setting volume: 82
I (40940) SC: fLaC sampleformat: 44100:16:2
I (40946) SC: latency buffer full
E (68511) esp_netif_handlers: invalid static ip
I (68512) ETH_IF: Ethernet Link Up
I (68512) ETH_IF: Ethernet HW Addr xxxxxxxxxxxx
I (68516) ETH_IF: Ethernet present and WiFi active; will prefer Ethernet after IP acquired
I (68525) ETH_IF: DHCP client started
I (69525) esp_netif_handlers: eth ip: 192.168.1.106, mask: 255.255.255.0, gw: 192.168.1.2
I (69525) ETH_IF: Ethernet Got IP Address
I (69527) ETH_IF: ~~~~~~~~~~~
I (69531) ETH_IF: ETHIP:192.168.1.106
I (69535) ETH_IF: ETHMASK:255.255.255.0
I (69540) ETH_IF: ETHGW:192.168.1.2
I (69544) ETH_IF: ~~~~~~~~~~~
I (69548) ETH_IF: Ethernet takeover: setting default netif to ETH
I (69558) SC: Reconnect requested during receive loop, breaking out

assert failed: tlsf_free tlsf.c:1120 (!block_is_free(block) && "block already marked as free")


Backtrace: 0x40081c4e:0x3ffd6d20 0x4008c2b9:0x3ffd6d40 0x400907a1:0x3ffd6d60 0x4008ee79:0x3ffd6e80 0x4008ed4e:0x3ffd6ea0 0x400824d7:0x3ffd6ec0 0x400907fd:0x3ffd6ee0 0x40112d95:0x3ffd6f00 0x40112e3a:0x3ffd6f20 0x4010eb36:0x3ffd6f40 0x400d856a:0x3ffd6f60
--- 0x40081c4e: panic_abort at /home/karl/espressif/esp-idf/components/esp_system/panic.c:466
0x4008c2b9: esp_system_abort at /home/karl/espressif/esp-idf/components/esp_system/port/esp_system_chip.c:84
0x400907a1: __assert_func at /home/karl/espressif/esp-idf/components/newlib/assert.c:81
0x4008ee79: tlsf_free at /home/karl/espressif/esp-idf/components/heap/tlsf/tlsf.c:1120 (discriminator 1)
0x4008ed4e: multi_heap_free_impl at /home/karl/espressif/esp-idf/components/heap/multi_heap.c:231
 (inlined by) multi_heap_free_impl at /home/karl/espressif/esp-idf/components/heap/multi_heap.c:220
0x400824d7: heap_caps_free at /home/karl/espressif/esp-idf/components/heap/heap_caps_base.c:64
0x400907fd: free at /home/karl/espressif/esp-idf/components/newlib/heap.c:39
0x40112d95: mem_free at /home/karl/espressif/esp-idf/components/lwip/lwip/src/core/mem.c:236 (discriminator 2)
0x40112e3a: do_memp_free_pool at /home/karl/espressif/esp-idf/components/lwip/lwip/src/core/memp.c:383
 (inlined by) memp_free at /home/karl/espressif/esp-idf/components/lwip/lwip/src/core/memp.c:440
0x4010eb36: netbuf_delete at /home/karl/espressif/esp-idf/components/lwip/lwip/src/api/netbuf.c:88
0x400d856a: http_get_task at /home/karl/esp32-snapclient/main/main.c:951

Another thing, is there a reason why you disabled ethernet by default? I'd prefer to have it enabled on DHCP per default if ethernet is configured through menuconfig.

The above error doesn't seem to happen again now...

@craigmillard86
Copy link
Author

So I found some time to test this just now and found a Problem.

  1. start up with ethernet connected and wifi available. No audio from snapserver at all time
  2. disconnect ethernet cable. --> wifi fallback successful
  3. connect cable again --> device reboots
I (30512) ETH_IF: Ethernet disconnected; triggering WiFi fallback
I (30512) ETH_IF: Ethernet Link Down
W (30515) SC: error writing timesync msg
I (30520) SC: Wait for network connection
I (30527) SC: Default netif present but no IP yet: ETH_DEF
I (30531) SC: Reconnect requested: no active netconn (loop start)
I (32058) esp_netif_handlers: sta ip: 192.168.1.103, mask: 255.255.255.0, gw: 192.168.1.2
I (32058) WIFI_IF: Wifi Got IP Address
I (32060) WIFI_IF: ~~~~~~~~~~~
I (32064) WIFI_IF: WIFIIP:192.168.1.103
I (32068) WIFI_IF: WIFIMASK:255.255.255.0
I (32073) WIFI_IF: WIFIGW:192.168.1.2
I (32077) WIFI_IF: ~~~~~~~~~~~
I (32587) SC: WiFi up, waiting for Ethernet (1/5)...
I (33587) SC: WiFi up, waiting for Ethernet (2/5)...
I (34587) SC: WiFi up, waiting for Ethernet (3/5)...
I (35587) SC: WiFi up, waiting for Ethernet (4/5)...
I (36587) SC: WiFi up, waiting for Ethernet (5/5)...
W (37587) SC: Ethernet not available, falling back to WiFi
I (37587) SC: Using WiFi interface
I (37587) SC: Enable mdns
I (37589) SC: Lookup snapcast service on network
I (40608) SC: 
~~~~~~~~~~ MDNS Query success ~~~~~~~~~~
I (40609) NETF: Interface: sta
I (40609) NETF: Type: V4
I (40610) NETF:   PTR : Snapcast
I (40614) NETF:   SRV : openmediavault-2.local:1704
I (40620) NETF:   A   : 192.168.1.16
I (40624) SC: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I (40630) SC: Found 192.168.1.16:1704
I (40634) SC: Binding netconn to interface WIFI_STA_DEF (idx 4)
I (40641) SC: Successfully bound netconn to WIFI_STA_DEF (idx 4)
I (40647) SC: Connecting to remote 192.168.1.16:1704 using local interface WIFI_STA_DEF
I (40915) SC: netconn connected using WIFI_STA_DEF
I (40916) SC: eth mac: xxxxxxxxxxxxxxxxxxxx
I (40916) SC: sta mac: xxxxxxxxxxxxxxxxxx
I (40921) SC: netconn sent hello message
I (40925) SC: Buffer length:  700
I (40927) SC: Latency:        0
I (40931) SC: Mute:           0
I (40935) SC: Setting volume: 82
I (40940) SC: fLaC sampleformat: 44100:16:2
I (40946) SC: latency buffer full
E (68511) esp_netif_handlers: invalid static ip
I (68512) ETH_IF: Ethernet Link Up
I (68512) ETH_IF: Ethernet HW Addr xxxxxxxxxxxx
I (68516) ETH_IF: Ethernet present and WiFi active; will prefer Ethernet after IP acquired
I (68525) ETH_IF: DHCP client started
I (69525) esp_netif_handlers: eth ip: 192.168.1.106, mask: 255.255.255.0, gw: 192.168.1.2
I (69525) ETH_IF: Ethernet Got IP Address
I (69527) ETH_IF: ~~~~~~~~~~~
I (69531) ETH_IF: ETHIP:192.168.1.106
I (69535) ETH_IF: ETHMASK:255.255.255.0
I (69540) ETH_IF: ETHGW:192.168.1.2
I (69544) ETH_IF: ~~~~~~~~~~~
I (69548) ETH_IF: Ethernet takeover: setting default netif to ETH
I (69558) SC: Reconnect requested during receive loop, breaking out

assert failed: tlsf_free tlsf.c:1120 (!block_is_free(block) && "block already marked as free")


Backtrace: 0x40081c4e:0x3ffd6d20 0x4008c2b9:0x3ffd6d40 0x400907a1:0x3ffd6d60 0x4008ee79:0x3ffd6e80 0x4008ed4e:0x3ffd6ea0 0x400824d7:0x3ffd6ec0 0x400907fd:0x3ffd6ee0 0x40112d95:0x3ffd6f00 0x40112e3a:0x3ffd6f20 0x4010eb36:0x3ffd6f40 0x400d856a:0x3ffd6f60
--- 0x40081c4e: panic_abort at /home/karl/espressif/esp-idf/components/esp_system/panic.c:466
0x4008c2b9: esp_system_abort at /home/karl/espressif/esp-idf/components/esp_system/port/esp_system_chip.c:84
0x400907a1: __assert_func at /home/karl/espressif/esp-idf/components/newlib/assert.c:81
0x4008ee79: tlsf_free at /home/karl/espressif/esp-idf/components/heap/tlsf/tlsf.c:1120 (discriminator 1)
0x4008ed4e: multi_heap_free_impl at /home/karl/espressif/esp-idf/components/heap/multi_heap.c:231
 (inlined by) multi_heap_free_impl at /home/karl/espressif/esp-idf/components/heap/multi_heap.c:220
0x400824d7: heap_caps_free at /home/karl/espressif/esp-idf/components/heap/heap_caps_base.c:64
0x400907fd: free at /home/karl/espressif/esp-idf/components/newlib/heap.c:39
0x40112d95: mem_free at /home/karl/espressif/esp-idf/components/lwip/lwip/src/core/mem.c:236 (discriminator 2)
0x40112e3a: do_memp_free_pool at /home/karl/espressif/esp-idf/components/lwip/lwip/src/core/memp.c:383
 (inlined by) memp_free at /home/karl/espressif/esp-idf/components/lwip/lwip/src/core/memp.c:440
0x4010eb36: netbuf_delete at /home/karl/espressif/esp-idf/components/lwip/lwip/src/api/netbuf.c:88
0x400d856a: http_get_task at /home/karl/esp32-snapclient/main/main.c:951

Another thing, is there a reason why you disabled ethernet by default? I'd prefer to have it enabled on DHCP per default if ethernet is configured through menuconfig.

The above error doesn't seem to happen again now...

I thought i had it set to DHCP by default - unsure why its default is disabled now..

Is it now not crashing? I havent seen this on my boards which is interesting, I have had occasions where i was testing with rapid dicsonnections from ethernet to wifi and back where the server didnt close the connections and continued to use to old route once the device became availble again. That looked like a server issue rather than client as the client cannot inform the server that the connection is on a new route.

As its failover i didnt see it as too much of an issue as majority of users will just want to have both enabled with DHCP and be able to move them around the house which will give enough time for timeouts to occur on the server and clear the routes etc.

@CarlosDerSeher
Copy link
Owner

CarlosDerSeher commented Feb 7, 2026

No the reboot just happened once, from the back trace it even seems unrelated maybe?

@CarlosDerSeher
Copy link
Owner

CarlosDerSeher commented Feb 7, 2026

I (7535) ETH_IF: Ethernet takeover: setting default netif to ETH
I (7636) SC: Reconnect requested: no active netconn (loop start)
I (7686) SC: Using Ethernet interface

E (7689) wifi:NAN WiFi stop

I (7729) SC: WiFi disabled (Ethernet active)

is there any possibility to avoid this error?

Copilot AI review requested due to automatic review settings February 7, 2026 18:26
@craigmillard86
Copy link
Author

I (7535) ETH_IF: Ethernet takeover: setting default netif to ETH
I (7636) SC: Reconnect requested: no active netconn (loop start)
I (7686) SC: Using Ethernet interface
E (7689) wifi:NAN WiFi stop
I (7729) SC: WiFi disabled (Ethernet active)

is there any possibility to avoid this error?

I have added a disconnect first before stopping which should stop this error

@craigmillard86
Copy link
Author

No the reboot just happened once, from the back trace it even seems unrelated maybe?

It was always a bug in the code but never impacted until these changes, have correctly NULLed now.

@craigmillard86
Copy link
Author

DHCP is now default for Ethernet as well

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors networking into a unified Ethernet/WiFi management approach, adding coordinated handover (Ethernet priority with deferred takeover during playback) plus user-configurable Ethernet static IP settings exposed via the web UI.

Changes:

  • Added FreeRTOS EventGroup-based signaling for reconnect requests and playback start/stop coordination.
  • Implemented Ethernet priority/failover logic (including DHCP restart on reconnect) and added static-IP configuration persisted in NVS.
  • Extended the HTTP UI/backend to configure/clear/read Ethernet mode + static IP/gateway/netmask/DNS and added a global “Restart Device” button.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
main/main.c Binds snapclient connection to the preferred/default netif, adds reconnect handling, and initializes network events before network init.
components/ui_http_server/ui_http_server.c Adds REST handlers for Ethernet settings (GET/POST/DELETE) and keeps /restart endpoint.
components/ui_http_server/html/index.html Adds a global “Restart Device” button in the nav bar.
components/ui_http_server/html/general-settings.html Adds Ethernet configuration UI (mode + static IP fields) and client-side validation/CRUD.
components/settings_manager/settings_manager.c Persists Ethernet mode and static IP parameters in NVS and exposes them via JSON.
components/settings_manager/include/settings_manager.h Declares Ethernet settings APIs.
components/network_interface/network_interface.c Adds EventGroup-based reconnect/playback signaling and a network_has_ip() helper.
components/network_interface/include/network_interface.h Exposes new network event APIs and network_has_ip().
components/network_interface/priv_include/network_interface_priv.h Adds internal-only network_interface APIs for other files within the component.
components/network_interface/eth_interface.c Major rewrite: takeover logic, static IP apply + gateway reachability ping, DHCP restart, playback-deferral logic.
components/network_interface/wifi_interface.c Pulls in private header for internal helpers.
components/network_interface/CMakeLists.txt Makes Ethernet source conditional and adds private include dir + dependencies.
components/lightsnapcast/player.c Signals playback start/stop to the network layer; adds guards to avoid restart races.
components/lightsnapcast/CMakeLists.txt Adds dependency on network_interface.
Comments suppressed due to low confidence (1)

components/lightsnapcast/player.c:503

  • network_playback_started() is called before player_setup_i2s() succeeds. If player_setup_i2s() fails, the function returns without sending network_playback_stopped(), leaving the network layer thinking playback is active (which can indefinitely defer Ethernet takeover/static-IP work). Move the playback-start signal until after all failure points, or ensure all error returns also signal playback stopped.
    // Clear shutdown flag - we're starting a new session
    player_shutdown_in_progress = false;
    playerstarted = true;
    if (network_playback_started() != ESP_OK) {
        ESP_LOGW(TAG, "Failed to signal playback started to network layer");
    }
  int ret = 0;

  ret = player_setup_i2s(setting);
  if (ret < 0) {
    ESP_LOGE(TAG, "player_setup_i2s failed: %d", ret);
    playerstarted = false;
    return -1;
  }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@CarlosDerSeher
Copy link
Owner

CarlosDerSeher commented Feb 7, 2026

I still see E (3490) wifi:NAN WiFi stop

Another thing I think that could be useful, when music is playing and I disconnect the cable it takes quite long until playback resumes from wifi. Do you think it would be possible to speed up this process if music was active while ethernet disconnection? And also the other way around maybe?

Also there is E (168310) esp_netif_handlers: invalid static ip this and then continues with normal ethernet ip etc process.

Other than that, it seems to work as advertised :)

@craigmillard86
Copy link
Author

E (3490) wifi:NAN WiFi stop

ah ok, so NAN is a bug in 5.1.5 espressif/esp-idf#12473 - harmless but incorrect log level.

The E (168310) esp_netif_handlers: invalid static ip error - happens because we stop DHCP on disconnect, and it doesn't automatically restart on reconnect - causing "invalid static ip" errors until the IP is applied. DHCP is stopped for a reason (avoid confusion during static IP transitions).

Another thing I think that could be useful, when music is playing and I disconnect the cable it takes quite long until playback resumes from wifi. Do you think it would be possible to speed up this process if music was active while ethernet disconnection? And also the other way around maybe? -
On wifi fallback the device has to start wifi and get dhcp ip then sync up to the server, this was taking about 5s on my device. I did try to get it working with Wifi staying on all the time but the ESP and server would continually get confused about which IP/device is the active route.
The otherway round when ethernet is plugged in the esp will wait for playback stop before transitioning over to avoid interuptions in the playback

@CarlosDerSeher
Copy link
Owner

Ok. Thanks for clarification 👍

@CarlosDerSeher
Copy link
Owner

One more thing, you are writing about stale connections in your commit message, could this origin from using wifi mac in snapcast hello message? I thought it was a good idea to use always the same mac because if not the server thinks we are two different devices. This would cause some issues for the user like volume and names being different suddenly. I guess this is still the best way of doing things though how about you?

@CarlosDerSeher
Copy link
Owner

Another issue arised for me with current develop, I frequently get memory allocation errors/warnings on my devices with no PSRAM. In the past 750ms buffer was working without issues and I had to reduce this to 700ms maybe even less is needed I am not sure yet. Could you enable https://github.com/CarlosDerSeher/snapclient/blob/develop/main%2Fmain.c#L333 and so some comparison with current state vs your changes? How do those changes affect heap usage?

@CarlosDerSeher
Copy link
Owner

See #197

@CarlosDerSeher
Copy link
Owner

@craigmillard86 So I'd really like to merge this but I am a bit overwhelmed by the tons of commit messages. Could you please squash this to a single commit with a proper commit messages, concentrating on the actual changes/improvements?

@luar123 luar123 mentioned this pull request Feb 10, 2026
This commit consolidates 86 commits of development work implementing:

- Unified ethernet and WiFi network interface management
- Ethernet with static IP configuration support
- WiFi failover when ethernet disconnects
- Ethernet priority with automatic failover to WiFi
- IPv6 support with fallback to IPv4
- Improved network robustness and error handling
- Global restart button for network recovery
- Web UI for ethernet static IP configuration
- Proper cleanup and resource management
- Various bug fixes and stability improvements

Key changes:
- Merged separate ethernet and WiFi components into unified network interface
- Added persistent Ethernet static IP configuration via Kconfig
- Implemented proper connection state management with FreeRTOS EventGroups
- Added gateway reachability checks with IPv6 fallback
- Fixed race conditions in player startup/shutdown
- Improved DHCP restart handling
- Reduced buffer allocation for PSRAM-less devices (750ms -> 700ms)
@craigmillard86 craigmillard86 force-pushed the feature/unified-ethernet branch from 40af5de to 362ec8c Compare February 10, 2026 22:04
@craigmillard86
Copy link
Author

@craigmillard86 So I'd really like to merge this but I am a bit overwhelmed by the tons of commit messages. Could you please squash this to a single commit with a proper commit messages, concentrating on the actual changes/improvements?

Squashed, hopefully thats a little better!

@craigmillard86
Copy link
Author

closing this PR as moved to cherry pick branch and new PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants