From b8d8218428bde730417285ac34756c291196e3a9 Mon Sep 17 00:00:00 2001 From: Esteban Borai Date: Tue, 15 Jun 2021 01:09:08 -0400 Subject: [PATCH] init: initial commit --- .github/PULL_REQUEST_TEMPLATE.md | 27 +++ .github/workflows/build.yml | 30 ++++ .github/workflows/clippy.yml | 37 ++++ .github/workflows/fmt.yml | 39 +++++ .github/workflows/release.yml | 43 +++++ .gitignore | 55 ++++++ CODE_OF_CONDUCT.md | 76 +++++++++ CONTRIBUTING.md | 61 +++++++ Cargo.lock | 96 +++++++++++ Cargo.toml | 18 ++ LICENSE-APACHE | 201 ++++++++++++++++++++++ LICENSE-MIT | 25 +++ README.md | 69 ++++++++ rustfmt.toml | 278 +++++++++++++++++++++++++++++++ src/lib.rs | 89 ++++++++++ 15 files changed, 1144 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/clippy.yml create mode 100644 .github/workflows/fmt.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT create mode 100644 README.md create mode 100644 rustfmt.toml create mode 100644 src/lib.rs diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..2efb23b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,27 @@ + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..860239b --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,30 @@ +name: build +on: + pull_request: + push: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Cache .cargo and target + uses: actions/cache@v2 + with: + path: | + ~/.cargo + ./target + key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.toml') }} + restore-keys: | + ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }} + ${{ runner.os }}-cargo-build + + - name: cargo build + uses: actions-rs/cargo@v1 + with: + command: build + args: --release --locked diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml new file mode 100644 index 0000000..984b4f8 --- /dev/null +++ b/.github/workflows/clippy.yml @@ -0,0 +1,37 @@ +name: clippy +on: + pull_request: + push: + branches: + - main + +jobs: + clippy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: clippy + + - name: Cache .cargo and target + uses: actions/cache@v2 + with: + path: | + ~/.cargo + ./target + key: ${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.lock') }} + ${{ runner.os }}-cargo-clippy + + - name: cargo clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: -- -D warnings diff --git a/.github/workflows/fmt.yml b/.github/workflows/fmt.yml new file mode 100644 index 0000000..65a6649 --- /dev/null +++ b/.github/workflows/fmt.yml @@ -0,0 +1,39 @@ +name: fmt +on: + pull_request: + push: + branches: + - main + +jobs: + fmt: + name: fmt + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + components: rustfmt + + - name: Cache .cargo and target + uses: actions/cache@v2 + with: + path: | + ~/.cargo + ./target + key: ${{ runner.os }}-cargo-fmt-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo-fmt-${{ hashFiles('**/Cargo.lock') }} + ${{ runner.os }}-cargo-fmt + + - name: Run fmt + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..fadeee0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,43 @@ +name: release + +on: + push: + tags: + - 'v*' + +jobs: + create-release: + name: Create Release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + body: '' + draft: false + prerelease: false + + publish-crate: + name: Publish to crates.io + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + - run: cargo login ${CRATES_IO_TOKEN} + env: + CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} + + - name: publish crate + run: cargo publish diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..da1a46d --- /dev/null +++ b/.gitignore @@ -0,0 +1,55 @@ +# Development # +############### +.env + +# Application Related # +####################### +/target +/tmp + +# Compiled source # +################### +*.com +*.class +*.dll +*.exe +*.o +*.so +bundle + +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Logs and databases # +###################### +*.log +*.sqlite + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + + +# Cargo # +######### +/target + +# Editor Files # +################ +/.vscode diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..ca83468 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting estebanborai@gmail.com. + +All complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..23499eb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,61 @@ +# Contributing + +* [Code of Conduct](#code-of-conduct) +* [Pull Requests](#pull-requests) +* [Developer's Certificate of Origin 1.1](#developers-certificate-of-origin) + +## [Code of Conduct](./CODE_OF_CONDUCT.md) + +All individuals participating will be expected to abide by the Code of Conduct. + +Violating the Code of Conduct will result in action ranging from a conversation +about behavior to being permanently banned from the +project. + +### The Spirit of the law + +Not all interactions that require remediation are clear violations +of the Code of Conduct. Project maintainers will take appropriate +action, when neccessary, to ensure the zwnbsp community is a space +where individuals can comfortably collaborate and bring their +entire selves. Unfortunately, if bringing your entire self is +infringing on others from doing the same, you may be asked to leave. + +## Pull Requests + +If you would like to make a change open a Pull Request. + +Project maintainers will do their best to review and land code +in a reasonable time frame. + +All Pull Requests require CI to be green to land. + +It is possible that some Pull Requests may be rejected. The project +maintainers will make best effort to explain why a Pull Request is +rejected in a timely manner. + +## Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +* (a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +* (b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +* (c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +* (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b1236e0 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,96 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "local-ip-address" +version = "0.1.0" +dependencies = [ + "regex", + "thiserror", +] + +[[package]] +name = "memchr" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" + +[[package]] +name = "proc-macro2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "syn" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "thiserror" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b831c55 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "local-ip-address" +description = "Retrive system's local IP address" +repository = "https://github.com/EstebanBorai/local-ip-address" +categories = ["web-programming"] +homepage = "https://github.com/EstebanBorai/local-ip-address" +keywords = ["local", "ip", "address", "web", "network"] +license = "MIT OR Apache-2.0" +version = "0.1.0" +authors = ["Esteban Borai "] +edition = "2018" +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +regex = "1" +thiserror = "1" diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..6cf02d3 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2021 Esteban Borai and Contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c72eab9 --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +
+

local-ip-address

+

Retrive system's local IP address

+
+ +
+ + [![Crates.io](https://img.shields.io/crates/v/local-ip-address.svg)](https://crates.io/crates/local-ip-address) + [![Documentation](https://docs.rs/local-ip-address/badge.svg)](https://docs.rs/local-ip-address) + ![Build](https://github.com/EstebanBorai/local-ip-address/workflows/build/badge.svg) + ![Clippy](https://github.com/EstebanBorai/local-ip-address/workflows/clippy/badge.svg) + ![Formatter](https://github.com/EstebanBorai/local-ip-address/workflows/fmt/badge.svg) + +
+ +Provides utility functions to get system's local network IP address by executing +OS commands in the host machine. + +The output from the executed command is then parsed and an instance of a `IpAddr` +is returned from the function. + +```rust +use local_ip_address::local_ip; + +fn main() { + let my_local_ip_address = local_ip().unwrap(); + + println!("{:?}", my_local_ip_address); +} +``` + +Every host may or may not have a different approach on gathering the local IP +address. + +`local-ip-address` crate implements [Conditional Compilation](https://doc.rust-lang.org/reference/conditional-compilation.html#conditional-compilation) +to execute different approaches based on host machine operative system. + + +## Release + +In order to create a release you must push a Git tag as follows + +```sh +git tag -a -m +``` + +**Example** + +```sh +git tag -a v0.1.0 -m "First release" +``` + +> Tags must follow semver conventions +> Tags must be prefixed with a lowercase `v` letter. + +Then push tags as follows: + +```sh +git push origin main --follow-tags +``` + +## Contributing + +Every contribution to this project is welcome. Feel free to open a pull request, +an issue or just by starting this project. + +## License + +Distributed under the terms of both the MIT license and the Apache License (Version 2.0) diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..d4d60d2 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,278 @@ +# Use verbose output. +# Default: false +# verbose = + +# Do not reformat out of line modules. +# Default: false +# skip_children = + +# Lines to format; this is not supported in rustfmt.toml, +# and can only be specified via the --file-lines option. +# file_lines = + +# Maximum width of each line. +# Default: 100 +# max_width = + +# Ideal width of each line. +# Default: 80 +# max_width = + +# Number of spaces per tab. +# Default: 4 +# tab_spaces = 4 + +# Maximum width of the args of a function call before +# falling back to vertical formatting. +# Default: 60 +# fn_call_width = + +# Maximum width in the body of a struct lit before falling back to vertical formatting. +# Default: 16 +# struct_lit_width = + +# Maximum width in the body of a struct variant before falling back to vertical formatting. +# Default: 35 +# struct_variant_width = + +# Always print the abi for extern items. +# Default: true +# force_explicit_abi = + +# Unix or Windows line endings. +# Values: Windows | Unix | Native +# Default: Unix +# newline_style = + +# Brace style for functions. +# Values: AlwaysNextLine | PreferSameLine | SameLineWhere +# Default: SameLineWhere +# fn_brace_style = + +# Brace style for structs and enums. +# Values: AlwaysNextLine | PreferSameLine | SameLineWhere +# Default: SameLineWhere +# item_brace_style = + +# Brace style for control flow construct. +# Values: AlwaysSameLine | ClosingNextLine | AlwaysNextLine +# Default: AlwaysSameLine +# control_brace_style = + +# Put empty-body implementations on a single line. +# Default: true +# impl_empty_single_line = + +# Put empty-body functions on a single line. +# Default: true +# fn fn_empty_single_line = + +# Put single-expression functions on a single line. +# Default: false +# fn_single_line = + +# Location of return type in function declaration. +# Values: WithArgs | WithWhereClause +# Default: WithArgs +# fn_return_indent = + +# If function argument parenthesis goes on a newline. +# Default: true +# fn_args_paren_newline = + +# Argument density in functions. +# Values: Compressed | Tall | CompressedIfEmpty | Vertical +# Default: Tall +# fn_args_density = + +# Layout of function arguments. +# Values: Visual | Block | BlockAlways +# Default: Visual +# fn_args_layout = + +# Indent on function arguments. +# Values: Inherit | Tabbed | Visual +# Default: Visual +# fn_arg_indent = + +# Determines if '+' or '=' are wrapped in spaces in the punctuation of types. +# Values: Compressed | Wide +# Default: Wide +# type_punctuation_density = + +# Density of a where clause. +# Values: Compressed | Tall | CompressedIfEmpty | Vertical +# Default: CompressedIfEmpty +# where_density = + +# Indentation of a where clause. +# Values: Inherit | Tabbed | Visual +# Default: Tabbed +# where_indent = + +# Element layout inside a where clause. +# Values: Vertical | Horizontal | HorizontalVertical | Mixed +# Default: Vertical +# where_layout = + +# Indentation style of a where predicate. +# Values: Inherit | Tabbed | Visual +# Default: Visual +# where_pred_indent = + +# Put a trailing comma on where clauses. +# Default: false +# where_trailing_comma = + +# Indentation of generics. +# Values: Inherit | Tabbed | Visual +# Default: Visual +# generics_indent = + +# If there is a trailing comma on structs. +# Values: Always | Never | Vertical +# Default: Vertical +# struct_trailing_comma = + +# If there is a trailing comma on literal structs. +# Values: Always | Never | Vertical +# Default: Vertical +# struct_lit_trailing_comma = + +# Style of struct definition. +# Values: Visual | Block +# Default: Block +# struct_lit_style = + +# Multiline style on literal structs. +# Values: PreferSingle | ForceMulti +# Default: PreferSingle +# struct_lit_multiline_style = + +# Put a trailing comma on enum declarations. +# Default: true +# enum_trailing_comma = + +# Report all, none or unnumbered occurrences of TODO in source file comments. +# Values: Always | Unnumbered | Never +# Default: Never +# report_todo = + +# Report all, none or unnumbered occurrences of FIXME in source file comments. +# Values: Always | Unnumbered | Never +# Default: Never +# report_fixme = + +# Indent on chain base. +# Values: Inherit | Tabbed | Visual +# Default: Tabbed +# chain_base_indent = + +# Indentation of chain. +# Values: Inherit | Tabbed | Visual +# Default: Tabbed +# chain_indent = + +# Allow last call in method chain to break the line. +# Default: true +# chains_overflow_last = + +# Reorder import statements alphabetically. +# Default: false +# reorder_imports = + +# Reorder lists of names in import statements alphabetically. +# Default: false +# reorder_imported_names = + +# Maximum line length for single line if-else expressions. +# A value of zero means always break if-else expressions. +# Default: 50 +# single_line_if_else_max_width = + +# Format string literals where necessary. +# Default: true +# format_strings = + +# Always format string literals. +# Default: false +# force_format_strings = + +# Retain some formatting characteristics from the source code. +# Default: true +# take_source_hints = + +# Use tab characters for indentation, spaces for alignment. +# Default: false +# hard_tabs = + +# Break comments to fit on the line. +# Default: false +# wrap_comments = + +# Convert /* */ comments to // comments where possible. +# Default: false +# normalize_comments = + +# Wrap multiline match arms in blocks. +# Default: true +# wrap_match_arms = + +# Put a trailing comma after a block based match arm (non-block arms are not affected). +# Default: false +# match_block_trailing_comma = + +# Put a trailing comma after a wildcard arm. +# Default: true +# match_wildcard_trailing_comma = + +# How many lines a closure must have before it is block indented. +# -1 means never use block indent. +# Type: +# Default: 5 +# closure_block_indent_threshold = + +# Leave a space before the colon in a type annotation. +# Default: false +# space_before_type_annotation = + +# Leave a space after the colon in a type annotation. +# Default: true +# space_after_type_annotation_colon = + +# Leave a space before the colon in a trait or lifetime bound. +# Default: false +# space_before_bound = + +# Leave a space after the colon in a trait or lifetime bound. +# Default: true +# space_after_bound_colon = + +# Put spaces around the .. and ... range operators. +# Default: false +# spaces_around_ranges = + +# Put spaces within non-empty generic arguments. +# Default: false +# spaces_within_angle_brackets = + +# Put spaces within non-empty square brackets. +# Default: false +# spaces_within_square_brackets = + +# Put spaces within non-empty parentheses. +# Default: false +# spaces_within_parens = + +# Replace uses of the try! macro by the ? shorthand. +# Default: false +# use_try_shorthand = + +# What Write Mode to use when none is supplied: Replace, Overwrite, Display, Diff, Coverage. +# Values: Replace | Overwrite | Display | Diff | Coverage | Plain | Checkstyle +# Default: Replace +# write_mode = + +# Replace strings of _ wildcards by a single .. in tuple patterns. +# Default: false +# condense_wildcard_suffices = diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..8051b43 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,89 @@ +/*! +Provides utility functions to get system's local network IP address by executing +OS commands in the host machine. + +The output from the executed command is then parsed and an instance of a `IpAddr` +is returned from the function. + +```ignore +use local_ip_address::local_ip; + +fn main() { + let my_local_ip_address = local_ip().unwrap(); + + println!("{:?}", my_local_ip_address); +} +``` + +Every host may or may not have a different approach on gathering the local IP +address. + +`local-ip-address` crate implements [Conditional Compilation](https://doc.rust-lang.org/reference/conditional-compilation.html#conditional-compilation) +to execute different approaches based on host machine operative system. +*/ +use regex::Regex; +use std::env; +use std::net::{AddrParseError, IpAddr}; +use std::process::Command; +use std::str::FromStr; +use std::string::FromUtf8Error; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Invalid IP address, failed to parse `{0}` into an IP address")] + InvalidIpAddress(String, AddrParseError), + #[error("Invalid UTF-8 output found")] + InvalidUtf8(FromUtf8Error), + #[error("An error ocurred executing `{0}` on your platform (`{1}`)")] + CommandFailed(String, String, std::io::Error), + #[error("The current platform `{0}` is not supported.")] + PlatformNotSupported(String), + #[error("Failed to match IP from output. The following command output is not supported\n{0}")] + OutputNotSupported(String), +} + +pub type Result = std::result::Result; + +/// Executes a command locally to gather system's local IP address. +/// +/// Returns an `Err` with the `Error` variant `PlatformNotSupported` and the +/// name of the current platform name if theres no strategy available for this +/// platform. +pub fn local_ip() -> Result { + if cfg!(target_family = "unix") { + return unix(); + } + + Err(Error::PlatformNotSupported(env::consts::OS.to_string())) +} + +/// Unix strategy relies on executing `ipconfig` and extracting the IP address +/// from the command output using a regular expression. +/// +/// The executed command is: +/// +/// ```ignore +/// ipconfig getifaddr en0 +/// ``` +fn unix() -> Result { + let regex = Regex::new(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b").unwrap(); + let output = Command::new("ipconfig") + .arg("getifaddr") + .arg("en0") + .output() + .map_err(|error| { + Error::CommandFailed(String::from("ipconfig"), env::consts::OS.to_string(), error) + })?; + let ip_addr = String::from_utf8(output.stdout).map_err(Error::InvalidUtf8)?; + + if let Some(captures) = regex.captures(&ip_addr) { + if let Some(matches) = captures.get(0) { + return IpAddr::from_str(matches.as_str()) + .map_err(|error| Error::InvalidIpAddress(ip_addr.to_string(), error)); + } + + return Err(Error::OutputNotSupported(format!("{:?}", captures))); + } + + Err(Error::OutputNotSupported(ip_addr)) +}