init import
This commit is contained in:
Executable
+29
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
MAX_SIZE=1024 # 1 MB limit in KB
|
||||||
|
for file in $(git diff --cached --name-only --diff-filter=ACM); do
|
||||||
|
if [ ! -e "$file" ]; then continue; fi
|
||||||
|
size=$(du -k "$file" | cut -f1)
|
||||||
|
if [ $size -gt $MAX_SIZE ]; then
|
||||||
|
echo "Error: File $file is larger than the allowed size of $((MAX_SIZE / 1024)) MB."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
status=0
|
||||||
|
|
||||||
|
for file in $(git diff --cached --name-only | grep -E '\.go$'); do
|
||||||
|
badfile=$(gofmt -l "$file")
|
||||||
|
if test -n "$badfile" ; then
|
||||||
|
echo "Error: file needs gofmt: $badfile"
|
||||||
|
status=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# If any files were not formatted, exit with a non-zero status to abort the commit.
|
||||||
|
if [ "$status" -ne 0 ]; then
|
||||||
|
echo "git pre-commit check failed: some Go files are not formatted."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
exit 0
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
*~
|
||||||
|
autom4te.cache
|
||||||
|
Makefile
|
||||||
|
config.status
|
||||||
|
config.log
|
||||||
|
cmd/mbased/mbased
|
||||||
|
cmd/mbasectl/mbasectl
|
||||||
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
*.tar.*
|
||||||
|
*.tmp.*
|
||||||
|
*.tar
|
||||||
|
*.bin
|
||||||
|
tmp
|
||||||
|
mbased
|
||||||
|
mbasectl
|
||||||
|
DIST
|
||||||
|
*.tar.gz
|
||||||
|
*.deb
|
||||||
|
*.rpm
|
||||||
|
mbased.service
|
||||||
|
variant.go
|
||||||
|
initrc/mbased
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
FROM alpine:3.23 AS builder
|
||||||
|
|
||||||
|
RUN apk --no-cache add make binutils gcc libc-dev automake autoconf curl
|
||||||
|
RUN curl -o /usr/local/lib/go.tar.gz https://dl.google.com/go/go1.26.2.linux-amd64.tar.gz
|
||||||
|
RUN cd /usr/local/lib && tar xzf go.tar.gz
|
||||||
|
RUN cd /usr/local/bin && ln -sf ../lib/go/bin/* .
|
||||||
|
|
||||||
|
WORKDIR /app/src/
|
||||||
|
COPY go.mod go.sum .
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN ./configure --prefix=/app
|
||||||
|
RUN make all install
|
||||||
|
RUN make clean
|
||||||
|
RUN rm -rf /app/src
|
||||||
|
|
||||||
|
FROM alpine:3.23 AS runner
|
||||||
|
|
||||||
|
COPY --from=builder /app /app
|
||||||
|
RUN chmod 1777 /var
|
||||||
|
RUN mkdir -p /app/etc/mbase
|
||||||
|
RUN touch /app/etc/mbase/mbased.yaml
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
#USER daemon:daemon
|
||||||
|
ENTRYPOINT ["/app/sbin/mbased", "--asDaemon=false"]
|
||||||
+439
@@ -0,0 +1,439 @@
|
|||||||
|
|
||||||
|
Attribution-NonCommercial-ShareAlike 4.0 International
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||||
|
does not provide legal services or legal advice. Distribution of
|
||||||
|
Creative Commons public licenses does not create a lawyer-client or
|
||||||
|
other relationship. Creative Commons makes its licenses and related
|
||||||
|
information available on an "as-is" basis. Creative Commons gives no
|
||||||
|
warranties regarding its licenses, any material licensed under their
|
||||||
|
terms and conditions, or any related information. Creative Commons
|
||||||
|
disclaims all liability for damages resulting from their use to the
|
||||||
|
fullest extent possible.
|
||||||
|
|
||||||
|
Using Creative Commons Public Licenses
|
||||||
|
|
||||||
|
Creative Commons public licenses provide a standard set of terms and
|
||||||
|
conditions that creators and other rights holders may use to share
|
||||||
|
original works of authorship and other material subject to copyright
|
||||||
|
and certain other rights specified in the public license below. The
|
||||||
|
following considerations are for informational purposes only, are not
|
||||||
|
exhaustive, and do not form part of our licenses.
|
||||||
|
|
||||||
|
Considerations for licensors: Our public licenses are
|
||||||
|
intended for use by those authorized to give the public
|
||||||
|
permission to use material in ways otherwise restricted by
|
||||||
|
copyright and certain other rights. Our licenses are
|
||||||
|
irrevocable. Licensors should read and understand the terms
|
||||||
|
and conditions of the license they choose before applying it.
|
||||||
|
Licensors should also secure all rights necessary before
|
||||||
|
applying our licenses so that the public can reuse the
|
||||||
|
material as expected. Licensors should clearly mark any
|
||||||
|
material not subject to the license. This includes other CC-
|
||||||
|
licensed material, or material used under an exception or
|
||||||
|
limitation to copyright. More considerations for licensors:
|
||||||
|
wiki.creativecommons.org/Considerations_for_licensors
|
||||||
|
|
||||||
|
Considerations for the public: By using one of our public
|
||||||
|
licenses, a licensor grants the public permission to use the
|
||||||
|
licensed material under specified terms and conditions. If
|
||||||
|
the licensor's permission is not necessary for any reason--for
|
||||||
|
example, because of any applicable exception or limitation to
|
||||||
|
copyright--then that use is not regulated by the license. Our
|
||||||
|
licenses grant only permissions under copyright and certain
|
||||||
|
other rights that a licensor has authority to grant. Use of
|
||||||
|
the licensed material may still be restricted for other
|
||||||
|
reasons, including because others have copyright or other
|
||||||
|
rights in the material. A licensor may make special requests,
|
||||||
|
such as asking that all changes be marked or described.
|
||||||
|
Although not required by our licenses, you are encouraged to
|
||||||
|
respect those requests where reasonable. More considerations
|
||||||
|
for the public:
|
||||||
|
wiki.creativecommons.org/Considerations_for_licensees
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
|
||||||
|
Public License
|
||||||
|
|
||||||
|
By exercising the Licensed Rights (defined below), You accept and agree
|
||||||
|
to be bound by the terms and conditions of this Creative Commons
|
||||||
|
Attribution-NonCommercial-ShareAlike 4.0 International Public License
|
||||||
|
("Public License"). To the extent this Public License may be
|
||||||
|
interpreted as a contract, You are granted the Licensed Rights in
|
||||||
|
consideration of Your acceptance of these terms and conditions, and the
|
||||||
|
Licensor grants You such rights in consideration of benefits the
|
||||||
|
Licensor receives from making the Licensed Material available under
|
||||||
|
these terms and conditions.
|
||||||
|
|
||||||
|
|
||||||
|
Section 1 -- Definitions.
|
||||||
|
|
||||||
|
a. Adapted Material means material subject to Copyright and Similar
|
||||||
|
Rights that is derived from or based upon the Licensed Material
|
||||||
|
and in which the Licensed Material is translated, altered,
|
||||||
|
arranged, transformed, or otherwise modified in a manner requiring
|
||||||
|
permission under the Copyright and Similar Rights held by the
|
||||||
|
Licensor. For purposes of this Public License, where the Licensed
|
||||||
|
Material is a musical work, performance, or sound recording,
|
||||||
|
Adapted Material is always produced where the Licensed Material is
|
||||||
|
synched in timed relation with a moving image.
|
||||||
|
|
||||||
|
b. Adapter's License means the license You apply to Your Copyright
|
||||||
|
and Similar Rights in Your contributions to Adapted Material in
|
||||||
|
accordance with the terms and conditions of this Public License.
|
||||||
|
|
||||||
|
c. BY-NC-SA Compatible License means a license listed at
|
||||||
|
creativecommons.org/compatiblelicenses, approved by Creative
|
||||||
|
Commons as essentially the equivalent of this Public License.
|
||||||
|
|
||||||
|
d. Copyright and Similar Rights means copyright and/or similar rights
|
||||||
|
closely related to copyright including, without limitation,
|
||||||
|
performance, broadcast, sound recording, and Sui Generis Database
|
||||||
|
Rights, without regard to how the rights are labeled or
|
||||||
|
categorized. For purposes of this Public License, the rights
|
||||||
|
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||||
|
Rights.
|
||||||
|
|
||||||
|
e. Effective Technological Measures means those measures that, in the
|
||||||
|
absence of proper authority, may not be circumvented under laws
|
||||||
|
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||||
|
Treaty adopted on December 20, 1996, and/or similar international
|
||||||
|
agreements.
|
||||||
|
|
||||||
|
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||||
|
any other exception or limitation to Copyright and Similar Rights
|
||||||
|
that applies to Your use of the Licensed Material.
|
||||||
|
|
||||||
|
g. License Elements means the license attributes listed in the name
|
||||||
|
of a Creative Commons Public License. The License Elements of this
|
||||||
|
Public License are Attribution, NonCommercial, and ShareAlike.
|
||||||
|
|
||||||
|
h. Licensed Material means the artistic or literary work, database,
|
||||||
|
or other material to which the Licensor applied this Public
|
||||||
|
License.
|
||||||
|
|
||||||
|
i. Licensed Rights means the rights granted to You subject to the
|
||||||
|
terms and conditions of this Public License, which are limited to
|
||||||
|
all Copyright and Similar Rights that apply to Your use of the
|
||||||
|
Licensed Material and that the Licensor has authority to license.
|
||||||
|
|
||||||
|
j. Licensor means the individual(s) or entity(ies) granting rights
|
||||||
|
under this Public License.
|
||||||
|
|
||||||
|
k. NonCommercial means not primarily intended for or directed towards
|
||||||
|
commercial advantage or monetary compensation. For purposes of
|
||||||
|
this Public License, the exchange of the Licensed Material for
|
||||||
|
other material subject to Copyright and Similar Rights by digital
|
||||||
|
file-sharing or similar means is NonCommercial provided there is
|
||||||
|
no payment of monetary compensation in connection with the
|
||||||
|
exchange.
|
||||||
|
|
||||||
|
l. Share means to provide material to the public by any means or
|
||||||
|
process that requires permission under the Licensed Rights, such
|
||||||
|
as reproduction, public display, public performance, distribution,
|
||||||
|
dissemination, communication, or importation, and to make material
|
||||||
|
available to the public including in ways that members of the
|
||||||
|
public may access the material from a place and at a time
|
||||||
|
individually chosen by them.
|
||||||
|
|
||||||
|
m. Sui Generis Database Rights means rights other than copyright
|
||||||
|
resulting from Directive 96/9/EC of the European Parliament and of
|
||||||
|
the Council of 11 March 1996 on the legal protection of databases,
|
||||||
|
as amended and/or succeeded, as well as other essentially
|
||||||
|
equivalent rights anywhere in the world.
|
||||||
|
|
||||||
|
n. You means the individual or entity exercising the Licensed Rights
|
||||||
|
under this Public License. Your has a corresponding meaning.
|
||||||
|
|
||||||
|
|
||||||
|
Section 2 -- Scope.
|
||||||
|
|
||||||
|
a. License grant.
|
||||||
|
|
||||||
|
1. Subject to the terms and conditions of this Public License,
|
||||||
|
the Licensor hereby grants You a worldwide, royalty-free,
|
||||||
|
non-sublicensable, non-exclusive, irrevocable license to
|
||||||
|
exercise the Licensed Rights in the Licensed Material to:
|
||||||
|
|
||||||
|
a. reproduce and Share the Licensed Material, in whole or
|
||||||
|
in part, for NonCommercial purposes only; and
|
||||||
|
|
||||||
|
b. produce, reproduce, and Share Adapted Material for
|
||||||
|
NonCommercial purposes only.
|
||||||
|
|
||||||
|
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||||
|
Exceptions and Limitations apply to Your use, this Public
|
||||||
|
License does not apply, and You do not need to comply with
|
||||||
|
its terms and conditions.
|
||||||
|
|
||||||
|
3. Term. The term of this Public License is specified in Section
|
||||||
|
6(a).
|
||||||
|
|
||||||
|
4. Media and formats; technical modifications allowed. The
|
||||||
|
Licensor authorizes You to exercise the Licensed Rights in
|
||||||
|
all media and formats whether now known or hereafter created,
|
||||||
|
and to make technical modifications necessary to do so. The
|
||||||
|
Licensor waives and/or agrees not to assert any right or
|
||||||
|
authority to forbid You from making technical modifications
|
||||||
|
necessary to exercise the Licensed Rights, including
|
||||||
|
technical modifications necessary to circumvent Effective
|
||||||
|
Technological Measures. For purposes of this Public License,
|
||||||
|
simply making modifications authorized by this Section 2(a)
|
||||||
|
(4) never produces Adapted Material.
|
||||||
|
|
||||||
|
5. Downstream recipients.
|
||||||
|
|
||||||
|
a. Offer from the Licensor -- Licensed Material. Every
|
||||||
|
recipient of the Licensed Material automatically
|
||||||
|
receives an offer from the Licensor to exercise the
|
||||||
|
Licensed Rights under the terms and conditions of this
|
||||||
|
Public License.
|
||||||
|
|
||||||
|
b. Additional offer from the Licensor -- Adapted Material.
|
||||||
|
Every recipient of Adapted Material from You
|
||||||
|
automatically receives an offer from the Licensor to
|
||||||
|
exercise the Licensed Rights in the Adapted Material
|
||||||
|
under the conditions of the Adapter's License You apply.
|
||||||
|
|
||||||
|
c. No downstream restrictions. You may not offer or impose
|
||||||
|
any additional or different terms or conditions on, or
|
||||||
|
apply any Effective Technological Measures to, the
|
||||||
|
Licensed Material if doing so restricts exercise of the
|
||||||
|
Licensed Rights by any recipient of the Licensed
|
||||||
|
Material.
|
||||||
|
|
||||||
|
6. No endorsement. Nothing in this Public License constitutes or
|
||||||
|
may be construed as permission to assert or imply that You
|
||||||
|
are, or that Your use of the Licensed Material is, connected
|
||||||
|
with, or sponsored, endorsed, or granted official status by,
|
||||||
|
the Licensor or others designated to receive attribution as
|
||||||
|
provided in Section 3(a)(1)(A)(i).
|
||||||
|
|
||||||
|
b. Other rights.
|
||||||
|
|
||||||
|
1. Moral rights, such as the right of integrity, are not
|
||||||
|
licensed under this Public License, nor are publicity,
|
||||||
|
privacy, and/or other similar personality rights; however, to
|
||||||
|
the extent possible, the Licensor waives and/or agrees not to
|
||||||
|
assert any such rights held by the Licensor to the limited
|
||||||
|
extent necessary to allow You to exercise the Licensed
|
||||||
|
Rights, but not otherwise.
|
||||||
|
|
||||||
|
2. Patent and trademark rights are not licensed under this
|
||||||
|
Public License.
|
||||||
|
|
||||||
|
3. To the extent possible, the Licensor waives any right to
|
||||||
|
collect royalties from You for the exercise of the Licensed
|
||||||
|
Rights, whether directly or through a collecting society
|
||||||
|
under any voluntary or waivable statutory or compulsory
|
||||||
|
licensing scheme. In all other cases the Licensor expressly
|
||||||
|
reserves any right to collect such royalties, including when
|
||||||
|
the Licensed Material is used other than for NonCommercial
|
||||||
|
purposes.
|
||||||
|
|
||||||
|
|
||||||
|
Section 3 -- License Conditions.
|
||||||
|
|
||||||
|
Your exercise of the Licensed Rights is expressly made subject to the
|
||||||
|
following conditions.
|
||||||
|
|
||||||
|
a. Attribution.
|
||||||
|
|
||||||
|
1. If You Share the Licensed Material (including in modified
|
||||||
|
form), You must:
|
||||||
|
|
||||||
|
a. retain the following if it is supplied by the Licensor
|
||||||
|
with the Licensed Material:
|
||||||
|
|
||||||
|
i. identification of the creator(s) of the Licensed
|
||||||
|
Material and any others designated to receive
|
||||||
|
attribution, in any reasonable manner requested by
|
||||||
|
the Licensor (including by pseudonym if
|
||||||
|
designated);
|
||||||
|
|
||||||
|
ii. a copyright notice;
|
||||||
|
|
||||||
|
iii. a notice that refers to this Public License;
|
||||||
|
|
||||||
|
iv. a notice that refers to the disclaimer of
|
||||||
|
warranties;
|
||||||
|
|
||||||
|
v. a URI or hyperlink to the Licensed Material to the
|
||||||
|
extent reasonably practicable;
|
||||||
|
|
||||||
|
b. indicate if You modified the Licensed Material and
|
||||||
|
retain an indication of any previous modifications; and
|
||||||
|
|
||||||
|
c. indicate the Licensed Material is licensed under this
|
||||||
|
Public License, and include the text of, or the URI or
|
||||||
|
hyperlink to, this Public License.
|
||||||
|
|
||||||
|
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||||
|
reasonable manner based on the medium, means, and context in
|
||||||
|
which You Share the Licensed Material. For example, it may be
|
||||||
|
reasonable to satisfy the conditions by providing a URI or
|
||||||
|
hyperlink to a resource that includes the required
|
||||||
|
information.
|
||||||
|
3. If requested by the Licensor, You must remove any of the
|
||||||
|
information required by Section 3(a)(1)(A) to the extent
|
||||||
|
reasonably practicable.
|
||||||
|
|
||||||
|
b. ShareAlike.
|
||||||
|
|
||||||
|
In addition to the conditions in Section 3(a), if You Share
|
||||||
|
Adapted Material You produce, the following conditions also apply.
|
||||||
|
|
||||||
|
1. The Adapter's License You apply must be a Creative Commons
|
||||||
|
license with the same License Elements, this version or
|
||||||
|
later, or a BY-NC-SA Compatible License.
|
||||||
|
|
||||||
|
2. You must include the text of, or the URI or hyperlink to, the
|
||||||
|
Adapter's License You apply. You may satisfy this condition
|
||||||
|
in any reasonable manner based on the medium, means, and
|
||||||
|
context in which You Share Adapted Material.
|
||||||
|
|
||||||
|
3. You may not offer or impose any additional or different terms
|
||||||
|
or conditions on, or apply any Effective Technological
|
||||||
|
Measures to, Adapted Material that restrict exercise of the
|
||||||
|
rights granted under the Adapter's License You apply.
|
||||||
|
|
||||||
|
|
||||||
|
Section 4 -- Sui Generis Database Rights.
|
||||||
|
|
||||||
|
Where the Licensed Rights include Sui Generis Database Rights that
|
||||||
|
apply to Your use of the Licensed Material:
|
||||||
|
|
||||||
|
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||||
|
to extract, reuse, reproduce, and Share all or a substantial
|
||||||
|
portion of the contents of the database for NonCommercial purposes
|
||||||
|
only;
|
||||||
|
|
||||||
|
b. if You include all or a substantial portion of the database
|
||||||
|
contents in a database in which You have Sui Generis Database
|
||||||
|
Rights, then the database in which You have Sui Generis Database
|
||||||
|
Rights (but not its individual contents) is Adapted Material,
|
||||||
|
including for purposes of Section 3(b); and
|
||||||
|
|
||||||
|
c. You must comply with the conditions in Section 3(a) if You Share
|
||||||
|
all or a substantial portion of the contents of the database.
|
||||||
|
|
||||||
|
For the avoidance of doubt, this Section 4 supplements and does not
|
||||||
|
replace Your obligations under this Public License where the Licensed
|
||||||
|
Rights include other Copyright and Similar Rights.
|
||||||
|
|
||||||
|
|
||||||
|
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||||
|
|
||||||
|
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||||
|
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||||
|
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||||
|
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||||
|
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||||
|
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||||
|
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||||
|
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||||
|
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||||
|
|
||||||
|
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||||
|
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||||
|
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||||
|
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||||
|
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||||
|
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||||
|
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||||
|
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||||
|
|
||||||
|
c. The disclaimer of warranties and limitation of liability provided
|
||||||
|
above shall be interpreted in a manner that, to the extent
|
||||||
|
possible, most closely approximates an absolute disclaimer and
|
||||||
|
waiver of all liability.
|
||||||
|
|
||||||
|
|
||||||
|
Section 6 -- Term and Termination.
|
||||||
|
|
||||||
|
a. This Public License applies for the term of the Copyright and
|
||||||
|
Similar Rights licensed here. However, if You fail to comply with
|
||||||
|
this Public License, then Your rights under this Public License
|
||||||
|
terminate automatically.
|
||||||
|
|
||||||
|
b. Where Your right to use the Licensed Material has terminated under
|
||||||
|
Section 6(a), it reinstates:
|
||||||
|
|
||||||
|
1. automatically as of the date the violation is cured, provided
|
||||||
|
it is cured within 30 days of Your discovery of the
|
||||||
|
violation; or
|
||||||
|
|
||||||
|
2. upon express reinstatement by the Licensor.
|
||||||
|
|
||||||
|
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||||
|
right the Licensor may have to seek remedies for Your violations
|
||||||
|
of this Public License.
|
||||||
|
|
||||||
|
c. For the avoidance of doubt, the Licensor may also offer the
|
||||||
|
Licensed Material under separate terms or conditions or stop
|
||||||
|
distributing the Licensed Material at any time; however, doing so
|
||||||
|
will not terminate this Public License.
|
||||||
|
|
||||||
|
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||||
|
License.
|
||||||
|
|
||||||
|
|
||||||
|
Section 7 -- Other Terms and Conditions.
|
||||||
|
|
||||||
|
a. The Licensor shall not be bound by any additional or different
|
||||||
|
terms or conditions communicated by You unless expressly agreed.
|
||||||
|
|
||||||
|
b. Any arrangements, understandings, or agreements regarding the
|
||||||
|
Licensed Material not stated herein are separate from and
|
||||||
|
independent of the terms and conditions of this Public License.
|
||||||
|
|
||||||
|
|
||||||
|
Section 8 -- Interpretation.
|
||||||
|
|
||||||
|
a. For the avoidance of doubt, this Public License does not, and
|
||||||
|
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||||
|
conditions on any use of the Licensed Material that could lawfully
|
||||||
|
be made without permission under this Public License.
|
||||||
|
|
||||||
|
b. To the extent possible, if any provision of this Public License is
|
||||||
|
deemed unenforceable, it shall be automatically reformed to the
|
||||||
|
minimum extent necessary to make it enforceable. If the provision
|
||||||
|
cannot be reformed, it shall be severed from this Public License
|
||||||
|
without affecting the enforceability of the remaining terms and
|
||||||
|
conditions.
|
||||||
|
|
||||||
|
c. No term or condition of this Public License will be waived and no
|
||||||
|
failure to comply consented to unless expressly agreed to by the
|
||||||
|
Licensor.
|
||||||
|
|
||||||
|
d. Nothing in this Public License constitutes or may be interpreted
|
||||||
|
as a limitation upon, or waiver of, any privileges and immunities
|
||||||
|
that apply to the Licensor or You, including from the legal
|
||||||
|
processes of any jurisdiction or authority.
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Creative Commons is not a party to its public
|
||||||
|
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||||
|
its public licenses to material it publishes and in those instances
|
||||||
|
will be considered the “Licensor.” The text of the Creative Commons
|
||||||
|
public licenses is dedicated to the public domain under the CC0 Public
|
||||||
|
Domain Dedication. Except for the limited purpose of indicating that
|
||||||
|
material is shared under a Creative Commons public license or as
|
||||||
|
otherwise permitted by the Creative Commons policies published at
|
||||||
|
creativecommons.org/policies, Creative Commons does not authorize the
|
||||||
|
use of the trademark "Creative Commons" or any other trademark or logo
|
||||||
|
of Creative Commons without its prior written consent including,
|
||||||
|
without limitation, in connection with any unauthorized modifications
|
||||||
|
to any of its public licenses or any other arrangements,
|
||||||
|
understandings, or agreements concerning use of licensed material. For
|
||||||
|
the avoidance of doubt, this paragraph does not form part of the
|
||||||
|
public licenses.
|
||||||
|
|
||||||
|
Creative Commons may be contacted at creativecommons.org.
|
||||||
|
|
||||||
+280
@@ -0,0 +1,280 @@
|
|||||||
|
|
||||||
|
AUTOMAKE_OPTIONS = foreign no-dependencies no-installinfo
|
||||||
|
|
||||||
|
SUBDIRS = mans
|
||||||
|
|
||||||
|
GOFLAGS= -v
|
||||||
|
bin_PROGRAMS = mbasectl
|
||||||
|
sbin_PROGRAMS = mbased
|
||||||
|
|
||||||
|
mbasectl_SOURCES = \
|
||||||
|
cmd/mbasectl/main.go
|
||||||
|
|
||||||
|
EXTRA_mbasectl_SOURCES = \
|
||||||
|
cmd/mbasectl/util/util.go \
|
||||||
|
cmd/mbasectl/accountcmd/acccmd.go \
|
||||||
|
cmd/mbasectl/accountcmd/createacc.go \
|
||||||
|
cmd/mbasectl/accountcmd/creategrant.go \
|
||||||
|
cmd/mbasectl/accountcmd/delacc.go \
|
||||||
|
cmd/mbasectl/accountcmd/delgrant.go \
|
||||||
|
cmd/mbasectl/accountcmd/getacc.go \
|
||||||
|
cmd/mbasectl/accountcmd/getgrant.go \
|
||||||
|
cmd/mbasectl/accountcmd/grantcmd.go \
|
||||||
|
cmd/mbasectl/accountcmd/listacc.go \
|
||||||
|
cmd/mbasectl/accountcmd/listgrant.go \
|
||||||
|
cmd/mbasectl/accountcmd/printresp.go \
|
||||||
|
cmd/mbasectl/accountcmd/updacc.go \
|
||||||
|
cmd/mbasectl/accountcmd/updgrant.go
|
||||||
|
|
||||||
|
mbased_SOURCES = cmd/mbased/main.go
|
||||||
|
|
||||||
|
EXTRA_mbased_SOURCES = cmd/mbased/starter/starter.go
|
||||||
|
|
||||||
|
mbasectl$(EXEEXT): $(mbasectl_SOURCES) $(EXTRA_mbasectl_SOURCES) $(EXTRA_mbased_SOURCES)
|
||||||
|
env CGO_ENABLED=0 $(GO) build $(GOFLAGS) -o mbasectl$(EXEEXT) $(mbasectl_SOURCES)
|
||||||
|
|
||||||
|
mbased$(EXEEXT): $(mbased_SOURCES) $(EXTRA_mbased_SOURCES)
|
||||||
|
env CGO_ENABLED=1 $(GO) build $(GOFLAGS) -o mbased$(EXEEXT) $(mbased_SOURCES)
|
||||||
|
|
||||||
|
run: $(mbased_SOURCES)
|
||||||
|
cd cmd/mbased && env CGO_ENABLED=1 $(GO) run . --asDaemon=false --port=443
|
||||||
|
|
||||||
|
CWD=$(shell pwd)
|
||||||
|
|
||||||
|
EXTRA_mbased_SOURCES += \
|
||||||
|
app/accoper/createacc.go \
|
||||||
|
app/accoper/creategrant.go \
|
||||||
|
app/accoper/delacc.go \
|
||||||
|
app/accoper/delgrant.go \
|
||||||
|
app/accoper/getacc.go \
|
||||||
|
app/accoper/getgrant.go \
|
||||||
|
app/accoper/listacc.go \
|
||||||
|
app/accoper/listgrant.go \
|
||||||
|
app/accoper/operator.go \
|
||||||
|
app/accoper/updacc.go \
|
||||||
|
app/accoper/updgrant.go \
|
||||||
|
app/config/config.go \
|
||||||
|
app/config/variant.go \
|
||||||
|
app/handler/aaafunc.go \
|
||||||
|
app/handler/account.go \
|
||||||
|
app/handler/grant.go \
|
||||||
|
app/handler/handler.go \
|
||||||
|
app/handler/notfound.go \
|
||||||
|
app/handler/response.go \
|
||||||
|
app/handler/service.go \
|
||||||
|
app/locker/locker.go \
|
||||||
|
app/logger/logger.go \
|
||||||
|
app/maindb/account.go \
|
||||||
|
app/maindb/grant.go \
|
||||||
|
app/maindb/init.go \
|
||||||
|
app/maindb/maindb.go \
|
||||||
|
app/maindb/scheme.go \
|
||||||
|
app/router/bindobj.go \
|
||||||
|
app/router/context.go \
|
||||||
|
app/router/corsmw.go \
|
||||||
|
app/router/loggingmw.go \
|
||||||
|
app/router/pathc.go \
|
||||||
|
app/router/recovermw.go \
|
||||||
|
app/router/router.go \
|
||||||
|
app/server/server.go \
|
||||||
|
app/server/listen.go \
|
||||||
|
app/service/service.go \
|
||||||
|
\
|
||||||
|
app/servoper/operator.go \
|
||||||
|
app/servoper/service.go \
|
||||||
|
\
|
||||||
|
pkg/accntcli/client.go \
|
||||||
|
pkg/accntcli/createacc.go \
|
||||||
|
pkg/accntcli/creategrant.go \
|
||||||
|
pkg/accntcli/delacc.go \
|
||||||
|
pkg/accntcli/delgrant.go \
|
||||||
|
pkg/accntcli/getacc.go \
|
||||||
|
pkg/accntcli/getgrant.go \
|
||||||
|
pkg/accntcli/httpcall.go \
|
||||||
|
pkg/accntcli/listacc.go \
|
||||||
|
pkg/accntcli/listgrants.go \
|
||||||
|
pkg/accntcli/referer.go \
|
||||||
|
pkg/accntcli/servhello.go \
|
||||||
|
pkg/accntcli/updateacc.go \
|
||||||
|
pkg/accntcli/updgrant.go \
|
||||||
|
pkg/auxhttp/basic.go \
|
||||||
|
pkg/auxhttp/crange.go \
|
||||||
|
pkg/auxpwd/passwd.go \
|
||||||
|
pkg/auxtool/cleandir.go \
|
||||||
|
pkg/auxtool/fileex.go \
|
||||||
|
pkg/auxtool/randstr.go \
|
||||||
|
pkg/auxtool/tmpfile.go \
|
||||||
|
pkg/auxtool/unixnow.go \
|
||||||
|
pkg/auxutar/utar.go \
|
||||||
|
pkg/auxuuid/uuid.go \
|
||||||
|
pkg/auxx509/x509cert.go \
|
||||||
|
pkg/descr/account.go \
|
||||||
|
pkg/descr/grant.go \
|
||||||
|
pkg/descr/server.go \
|
||||||
|
pkg/terms/terms.go
|
||||||
|
|
||||||
|
|
||||||
|
EXTRA_DIST = vendor/* \
|
||||||
|
\
|
||||||
|
Containerfile \
|
||||||
|
go.mod \
|
||||||
|
go.sum \
|
||||||
|
LICENSE.txt \
|
||||||
|
README.md \
|
||||||
|
DEVEL.md \
|
||||||
|
\
|
||||||
|
test/file_test.go \
|
||||||
|
\
|
||||||
|
chart/Chart.yaml.in \
|
||||||
|
chart/.gitignore \
|
||||||
|
chart/.helmignore \
|
||||||
|
chart/templates/configmap.yaml \
|
||||||
|
chart/templates/deployment.yaml \
|
||||||
|
chart/templates/_imagepath.tpl \
|
||||||
|
chart/templates/_serviceport.tmpl \
|
||||||
|
chart/templates/service.yaml \
|
||||||
|
chart/templates/_storageclass.tpl \
|
||||||
|
chart/templates/_storagesize.tpl \
|
||||||
|
chart/templates/_userpass.tpl \
|
||||||
|
chart/templates/volumeclaim.yaml \
|
||||||
|
chart/values.yaml.in \
|
||||||
|
\
|
||||||
|
debian/changelog.in \
|
||||||
|
debian/compat \
|
||||||
|
debian/control.in \
|
||||||
|
debian/files \
|
||||||
|
debian/.gitignore \
|
||||||
|
debian/mbase-control.install \
|
||||||
|
debian/mbase-control.postinst \
|
||||||
|
debian/mbase-control.postrm \
|
||||||
|
debian/mbase-control.preinst \
|
||||||
|
debian/mbase-control.prerm \
|
||||||
|
debian/mbase-service.install \
|
||||||
|
debian/mbase-service.postinst \
|
||||||
|
debian/mbase-service.postrm \
|
||||||
|
debian/mbase-service.preinst \
|
||||||
|
debian/mbase-service.prerm \
|
||||||
|
debian/patches/series \
|
||||||
|
debian/README.Debian \
|
||||||
|
debian/rules \
|
||||||
|
debian/source/format \
|
||||||
|
debian/source/include-binaries \
|
||||||
|
debian/watch \
|
||||||
|
\
|
||||||
|
initrc/.gitignore \
|
||||||
|
initrc/mbased.in \
|
||||||
|
initrc/mbased.service.in \
|
||||||
|
\
|
||||||
|
app/locker/locker_test.go \
|
||||||
|
app/logger/logger_test.go \
|
||||||
|
app/maindb/file_test.go \
|
||||||
|
app/maindb/grant_test.go \
|
||||||
|
app/router/pathc_test.go \
|
||||||
|
app/router/router_test.go \
|
||||||
|
pkg/auxpwd/passwd_test.go \
|
||||||
|
pkg/auxx509/x509cert_test.go \
|
||||||
|
\
|
||||||
|
docs/helm-chart-manifest.json.txt \
|
||||||
|
docs/mbase.drawio \
|
||||||
|
docs/mbase.png \
|
||||||
|
docs/podman-manifest.json.txt
|
||||||
|
|
||||||
|
format:
|
||||||
|
@dirs=$$($(FIND) $(CWD)/app $(CWD)/cmd $(CWD)/pkg $(CWD)/test \
|
||||||
|
-name '*.go' | $(XARGS) -n1 dirname | $(SORT) | $(UNIQ)); \
|
||||||
|
for dir in $$dirs;do \
|
||||||
|
(echo "====$$dir===="; cd $$dir && $(GO) fmt .); \
|
||||||
|
done
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
cd test && $(GO) test -v .
|
||||||
|
|
||||||
|
|
||||||
|
DIST_DIR= $(shell pwd)/DIST
|
||||||
|
BUILD_DIR= $(shell pwd)/BUILD
|
||||||
|
|
||||||
|
IMAGE_REPO = localhost
|
||||||
|
IMAGE_NAME = $(PACKAGE_NAME):$(PACKAGE_VERSION)
|
||||||
|
IMAGE_TARNAME = $(PACKAGE_NAME)-$(PACKAGE_VERSION).img
|
||||||
|
IMAGE_CONTAINERFILE = Containerfile
|
||||||
|
|
||||||
|
image:: build-image
|
||||||
|
build-image: clean
|
||||||
|
# $(GO) mod vendor
|
||||||
|
mkdir -p $(DIST_DIR)
|
||||||
|
$(SUDO) $(PODMAN) build -t $(IMAGE_REPO)/$(IMAGE_NAME) -f $(IMAGE_CONTAINERFILE) .
|
||||||
|
rm -f $(DIST_DIR)/$(IMAGE_TARNAME)
|
||||||
|
$(SUDO) $(PODMAN) image save $(IMAGE_REPO)/$(IMAGE_NAME) --format oci-archive \
|
||||||
|
-o $(DIST_DIR)/$(IMAGE_TARNAME)
|
||||||
|
username=$$(whoami); \
|
||||||
|
$(SUDO) chown $$username $(DIST_DIR)/$(IMAGE_TARNAME)
|
||||||
|
# rm -rf vendor
|
||||||
|
|
||||||
|
CHART_NAME = $(PACKAGE_NAME)-$(PACKAGE_VERSION).tgz
|
||||||
|
|
||||||
|
chart:: build-chart
|
||||||
|
build-chart:
|
||||||
|
mkdir -p $(DIST_DIR)
|
||||||
|
$(HELM) package --destination $(DIST_DIR) chart/
|
||||||
|
|
||||||
|
$(DIST_ARCHIVES): dist
|
||||||
|
|
||||||
|
package:: debian-package
|
||||||
|
debian-package: $(DIST_ARCHIVES)
|
||||||
|
mkdir -p $(BUILD_DIR)
|
||||||
|
mv $(DIST_ARCHIVES) $(BUILD_DIR)
|
||||||
|
cd $(BUILD_DIR) && $(AMTAR) -xf $(DIST_ARCHIVES)
|
||||||
|
cd $(BUILD_DIR)/$(distdir) && ./configure --prefix=/usr
|
||||||
|
cd $(BUILD_DIR)/$(distdir) && $(MAKE) clean
|
||||||
|
cd $(BUILD_DIR)/$(distdir) && $(DPKGSOURCE) -i --before-build .
|
||||||
|
cd $(BUILD_DIR)/$(distdir) && $(DBUILDPACKAGE) -nc -us -uc -ui -i -b
|
||||||
|
mkdir -p $(DIST_DIR)
|
||||||
|
$(CP) $(BUILD_DIR)/*.deb $(DIST_DIR)
|
||||||
|
rm -rf $(BUILD_DIR)
|
||||||
|
|
||||||
|
FREEBSD_LOCALBASE = /usr/local
|
||||||
|
FREEBSD_RCDIR = $(FREEBSD_LOCALBASE)/etc/rc.d
|
||||||
|
LINUX_SYSTEMDDIR = /lib/systemd/system
|
||||||
|
|
||||||
|
install-data-local:
|
||||||
|
test -z $(DESTDIR)$(srv_confdir) || $(MKDIR_P) $(DESTDIR)$(srv_confdir)
|
||||||
|
test -z $(DESTDIR)$(srv_logdir) || $(MKDIR_P) $(DESTDIR)$(srv_logdir)
|
||||||
|
test -z $(DESTDIR)$(srv_rundir) || $(MKDIR_P) $(DESTDIR)$(srv_rundir)
|
||||||
|
test -z $(DESTDIR)$(srv_datadir) || $(MKDIR_P) $(DESTDIR)$(srv_datadir)
|
||||||
|
if FREEBSD_OS
|
||||||
|
test -z $(DESTDIR)$(FREEBSD_RCDIR) || $(MKDIR_P) $(DESTDIR)$(FREEBSD_RCDIR)
|
||||||
|
$(INSTALL_DATA) initrc/mbased $(DESTDIR)$(FREEBSD_RCDIR)
|
||||||
|
chmod a+x $(DESTDIR)$(FREEBSD_RCDIR)/mbased
|
||||||
|
endif
|
||||||
|
if LINUX_OS
|
||||||
|
if SYSTEMD
|
||||||
|
test -z $(DESTDIR)$(LINUX_SYSTEMDDIR) || $(MKDIR_P) $(DESTDIR)$(LINUX_SYSTEMDDIR)
|
||||||
|
$(INSTALL_DATA) initrc/mbased.service $(DESTDIR)$(LINUX_SYSTEMDDIR)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
clean-local:
|
||||||
|
$(FIND) $(CWD) -name '*~' | $(XARGS) rm -f
|
||||||
|
rm -rf autom4te.cache
|
||||||
|
rm -f cmd/mbased/mbased
|
||||||
|
rm -f cmd/mbasectl/mbasectl
|
||||||
|
# rm -rf tmp/
|
||||||
|
|
||||||
|
distclean-local:
|
||||||
|
rm -rf autom4te.cache
|
||||||
|
rm -rf $(DIST_DIR)
|
||||||
|
rm -rf tmp/
|
||||||
|
|
||||||
|
|
||||||
|
SWAG_OUTDIR = ./
|
||||||
|
SWAG_OPTS = --parseDependency \
|
||||||
|
--parseDepth 3 \
|
||||||
|
--exclude pkg,vendor \
|
||||||
|
--outputTypes yaml,json \
|
||||||
|
--output $(SWAG_OUTDIR)
|
||||||
|
|
||||||
|
apidoc:
|
||||||
|
mkdir -p $(SWAG_OUTDIR)
|
||||||
|
$(SWAG) init $(SWAG_OPTS) -g ./cmd/mbased/main.go
|
||||||
|
|
||||||
+1162
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,55 @@
|
|||||||
|
# mStore - multifunсtion Storage
|
||||||
|
|
||||||
|
Under contruction.
|
||||||
|
|
||||||
|
With the application you can store and share
|
||||||
|
- Any blobs
|
||||||
|
- Helm charts
|
||||||
|
- OCI images
|
||||||
|
|
||||||
|
## Copyright EN
|
||||||
|
|
||||||
|
Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
|
||||||
|
This work is published and licensed under a Creative CommonsAttribution-NonCommercial-ShareAlike 4.0 International License.
|
||||||
|
|
||||||
|
* Attribution — You must give appropriate credit,
|
||||||
|
provide a link to the license, and indicate if changes
|
||||||
|
were made. You may do so in any reasonable manner,
|
||||||
|
but not in any way that suggests the licensor endorses
|
||||||
|
you or your use.
|
||||||
|
|
||||||
|
* NonCommercial — You may not use the material for commercial purposes.
|
||||||
|
|
||||||
|
* ShareAlike — If you remix, transform, or build upon the material,
|
||||||
|
you must distribute your contributions under the same license
|
||||||
|
as the original.
|
||||||
|
|
||||||
|
Distribution of this work is permitted, but commercial usu are
|
||||||
|
strictly prohibited.
|
||||||
|
|
||||||
|
## Copyright RU
|
||||||
|
|
||||||
|
Права на данное произведение принадлежат Олег Бородин <onborodin@gmail.com> 2026
|
||||||
|
|
||||||
|
Это произведение распространяется под лицензией Creative Commons
|
||||||
|
Attribution-NonCommercial-NoDerivatives 4.0 International License
|
||||||
|
|
||||||
|
Разрешается распространение, при условии указания автора, произведенных изменений
|
||||||
|
и сохранении лицензии, но запрещаются коммерческое использование
|
||||||
|
данного произведения.
|
||||||
|
|
||||||
|
Вы можете свободно делиться, то есть копировать, распространять и передавать
|
||||||
|
другим лицам данное произведение при обязательном соблюдении следующих условий:
|
||||||
|
|
||||||
|
* Атрибуция: Вы должны атрибутировать произведение (указывать автора и источник)
|
||||||
|
в порядке, предусмотренном автором или лицензиаром.
|
||||||
|
|
||||||
|
* Некоммерческое использование: Вы не можете использовать это произведение
|
||||||
|
в коммерческих целях, в целях получения выгоды или оплаты.
|
||||||
|
|
||||||
|
* Распостранять аналогично: Если вы перерабатываете, преобразуете или
|
||||||
|
создаете производные произведения на основе данного материала,
|
||||||
|
вы должны распространять свои результаты на условиях той же лицензии,
|
||||||
|
что и оригинал.
|
||||||
|
|
||||||
Vendored
+977
@@ -0,0 +1,977 @@
|
|||||||
|
# generated automatically by aclocal 1.17 -*- Autoconf -*-
|
||||||
|
|
||||||
|
# Copyright (C) 1996-2024 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||||
|
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
# PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
|
||||||
|
m4_ifndef([AC_AUTOCONF_VERSION],
|
||||||
|
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
||||||
|
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.72],,
|
||||||
|
[m4_warning([this file was generated for autoconf 2.72.
|
||||||
|
You have another version of autoconf. It may work, but is not guaranteed to.
|
||||||
|
If you have problems, you may need to regenerate the build system entirely.
|
||||||
|
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
|
||||||
|
|
||||||
|
# Copyright (C) 2002-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# AM_AUTOMAKE_VERSION(VERSION)
|
||||||
|
# ----------------------------
|
||||||
|
# Automake X.Y traces this macro to ensure aclocal.m4 has been
|
||||||
|
# generated from the m4 files accompanying Automake X.Y.
|
||||||
|
# (This private macro should not be called outside this file.)
|
||||||
|
AC_DEFUN([AM_AUTOMAKE_VERSION],
|
||||||
|
[am__api_version='1.17'
|
||||||
|
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
|
||||||
|
dnl require some minimum version. Point them to the right macro.
|
||||||
|
m4_if([$1], [1.17], [],
|
||||||
|
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
|
||||||
|
])
|
||||||
|
|
||||||
|
# _AM_AUTOCONF_VERSION(VERSION)
|
||||||
|
# -----------------------------
|
||||||
|
# aclocal traces this macro to find the Autoconf version.
|
||||||
|
# This is a private macro too. Using m4_define simplifies
|
||||||
|
# the logic in aclocal, which can simply ignore this definition.
|
||||||
|
m4_define([_AM_AUTOCONF_VERSION], [])
|
||||||
|
|
||||||
|
# AM_SET_CURRENT_AUTOMAKE_VERSION
|
||||||
|
# -------------------------------
|
||||||
|
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
|
||||||
|
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
|
||||||
|
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
|
||||||
|
[AM_AUTOMAKE_VERSION([1.17])dnl
|
||||||
|
m4_ifndef([AC_AUTOCONF_VERSION],
|
||||||
|
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
||||||
|
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
|
||||||
|
|
||||||
|
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
|
||||||
|
|
||||||
|
# Copyright (C) 2001-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
|
||||||
|
# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to
|
||||||
|
# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
|
||||||
|
#
|
||||||
|
# Of course, Automake must honor this variable whenever it calls a
|
||||||
|
# tool from the auxiliary directory. The problem is that $srcdir (and
|
||||||
|
# therefore $ac_aux_dir as well) can be either absolute or relative,
|
||||||
|
# depending on how configure is run. This is pretty annoying, since
|
||||||
|
# it makes $ac_aux_dir quite unusable in subdirectories: in the top
|
||||||
|
# source directory, any form will work fine, but in subdirectories a
|
||||||
|
# relative path needs to be adjusted first.
|
||||||
|
#
|
||||||
|
# $ac_aux_dir/missing
|
||||||
|
# fails when called from a subdirectory if $ac_aux_dir is relative
|
||||||
|
# $top_srcdir/$ac_aux_dir/missing
|
||||||
|
# fails if $ac_aux_dir is absolute,
|
||||||
|
# fails when called from a subdirectory in a VPATH build with
|
||||||
|
# a relative $ac_aux_dir
|
||||||
|
#
|
||||||
|
# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
|
||||||
|
# are both prefixed by $srcdir. In an in-source build this is usually
|
||||||
|
# harmless because $srcdir is '.', but things will broke when you
|
||||||
|
# start a VPATH build or use an absolute $srcdir.
|
||||||
|
#
|
||||||
|
# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
|
||||||
|
# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
|
||||||
|
# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
|
||||||
|
# and then we would define $MISSING as
|
||||||
|
# MISSING="\${SHELL} $am_aux_dir/missing"
|
||||||
|
# This will work as long as MISSING is not called from configure, because
|
||||||
|
# unfortunately $(top_srcdir) has no meaning in configure.
|
||||||
|
# However there are other variables, like CC, which are often used in
|
||||||
|
# configure, and could therefore not use this "fixed" $ac_aux_dir.
|
||||||
|
#
|
||||||
|
# Another solution, used here, is to always expand $ac_aux_dir to an
|
||||||
|
# absolute PATH. The drawback is that using absolute paths prevent a
|
||||||
|
# configured tree to be moved without reconfiguration.
|
||||||
|
|
||||||
|
AC_DEFUN([AM_AUX_DIR_EXPAND],
|
||||||
|
[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
|
||||||
|
# Expand $ac_aux_dir to an absolute path.
|
||||||
|
am_aux_dir=`cd "$ac_aux_dir" && pwd`
|
||||||
|
])
|
||||||
|
|
||||||
|
# AM_CONDITIONAL -*- Autoconf -*-
|
||||||
|
|
||||||
|
# Copyright (C) 1997-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
|
||||||
|
# -------------------------------------
|
||||||
|
# Define a conditional.
|
||||||
|
AC_DEFUN([AM_CONDITIONAL],
|
||||||
|
[AC_PREREQ([2.52])dnl
|
||||||
|
m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
|
||||||
|
[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
|
||||||
|
AC_SUBST([$1_TRUE])dnl
|
||||||
|
AC_SUBST([$1_FALSE])dnl
|
||||||
|
_AM_SUBST_NOTMAKE([$1_TRUE])dnl
|
||||||
|
_AM_SUBST_NOTMAKE([$1_FALSE])dnl
|
||||||
|
m4_define([_AM_COND_VALUE_$1], [$2])dnl
|
||||||
|
if $2; then
|
||||||
|
$1_TRUE=
|
||||||
|
$1_FALSE='#'
|
||||||
|
else
|
||||||
|
$1_TRUE='#'
|
||||||
|
$1_FALSE=
|
||||||
|
fi
|
||||||
|
AC_CONFIG_COMMANDS_PRE(
|
||||||
|
[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
|
||||||
|
AC_MSG_ERROR([[conditional "$1" was never defined.
|
||||||
|
Usually this means the macro was only invoked conditionally.]])
|
||||||
|
fi])])
|
||||||
|
|
||||||
|
# AM_EXTRA_RECURSIVE_TARGETS -*- Autoconf -*-
|
||||||
|
|
||||||
|
# Copyright (C) 2012-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# AM_EXTRA_RECURSIVE_TARGETS
|
||||||
|
# --------------------------
|
||||||
|
# Define the list of user recursive targets. This macro exists only to
|
||||||
|
# be traced by Automake, which will ensure that a proper definition of
|
||||||
|
# user-defined recursive targets (and associated rules) is propagated
|
||||||
|
# into all the generated Makefiles.
|
||||||
|
# TODO: We should really reject non-literal arguments here...
|
||||||
|
AC_DEFUN([AM_EXTRA_RECURSIVE_TARGETS], [])
|
||||||
|
|
||||||
|
# Do all the work for Automake. -*- Autoconf -*-
|
||||||
|
|
||||||
|
# Copyright (C) 1996-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# This macro actually does too much. Some checks are only needed if
|
||||||
|
# your package does certain things. But this isn't really a big deal.
|
||||||
|
|
||||||
|
dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
|
||||||
|
m4_define([AC_PROG_CC],
|
||||||
|
m4_defn([AC_PROG_CC])
|
||||||
|
[_AM_PROG_CC_C_O
|
||||||
|
])
|
||||||
|
|
||||||
|
# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
|
||||||
|
# AM_INIT_AUTOMAKE([OPTIONS])
|
||||||
|
# -----------------------------------------------
|
||||||
|
# The call with PACKAGE and VERSION arguments is the old style
|
||||||
|
# call (pre autoconf-2.50), which is being phased out. PACKAGE
|
||||||
|
# and VERSION should now be passed to AC_INIT and removed from
|
||||||
|
# the call to AM_INIT_AUTOMAKE.
|
||||||
|
# We support both call styles for the transition. After
|
||||||
|
# the next Automake release, Autoconf can make the AC_INIT
|
||||||
|
# arguments mandatory, and then we can depend on a new Autoconf
|
||||||
|
# release and drop the old call support.
|
||||||
|
AC_DEFUN([AM_INIT_AUTOMAKE],
|
||||||
|
[AC_PREREQ([2.65])dnl
|
||||||
|
m4_ifdef([_$0_ALREADY_INIT],
|
||||||
|
[m4_fatal([$0 expanded multiple times
|
||||||
|
]m4_defn([_$0_ALREADY_INIT]))],
|
||||||
|
[m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl
|
||||||
|
dnl Autoconf wants to disallow AM_ names. We explicitly allow
|
||||||
|
dnl the ones we care about.
|
||||||
|
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
|
||||||
|
AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
|
||||||
|
AC_REQUIRE([AC_PROG_INSTALL])dnl
|
||||||
|
if test "`cd $srcdir && pwd`" != "`pwd`"; then
|
||||||
|
# Use -I$(srcdir) only when $(srcdir) != ., so that make's output
|
||||||
|
# is not polluted with repeated "-I."
|
||||||
|
AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
|
||||||
|
# test to see if srcdir already configured
|
||||||
|
if test -f $srcdir/config.status; then
|
||||||
|
AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# test whether we have cygpath
|
||||||
|
if test -z "$CYGPATH_W"; then
|
||||||
|
if (cygpath --version) >/dev/null 2>/dev/null; then
|
||||||
|
CYGPATH_W='cygpath -w'
|
||||||
|
else
|
||||||
|
CYGPATH_W=echo
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AC_SUBST([CYGPATH_W])
|
||||||
|
|
||||||
|
# Define the identity of the package.
|
||||||
|
dnl Distinguish between old-style and new-style calls.
|
||||||
|
m4_ifval([$2],
|
||||||
|
[AC_DIAGNOSE([obsolete],
|
||||||
|
[$0: two- and three-arguments forms are deprecated.])
|
||||||
|
m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
|
||||||
|
AC_SUBST([PACKAGE], [$1])dnl
|
||||||
|
AC_SUBST([VERSION], [$2])],
|
||||||
|
[_AM_SET_OPTIONS([$1])dnl
|
||||||
|
dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
|
||||||
|
m4_if(
|
||||||
|
m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]),
|
||||||
|
[ok:ok],,
|
||||||
|
[m4_fatal([AC_INIT should be called with package and version arguments])])dnl
|
||||||
|
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
|
||||||
|
AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
|
||||||
|
|
||||||
|
_AM_IF_OPTION([no-define],,
|
||||||
|
[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
|
||||||
|
AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
|
||||||
|
|
||||||
|
# Some tools Automake needs.
|
||||||
|
AC_REQUIRE([AM_SANITY_CHECK])dnl
|
||||||
|
AC_REQUIRE([AC_ARG_PROGRAM])dnl
|
||||||
|
AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
|
||||||
|
AM_MISSING_PROG([AUTOCONF], [autoconf])
|
||||||
|
AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
|
||||||
|
AM_MISSING_PROG([AUTOHEADER], [autoheader])
|
||||||
|
AM_MISSING_PROG([MAKEINFO], [makeinfo])
|
||||||
|
AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
|
||||||
|
AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
|
||||||
|
AC_REQUIRE([AC_PROG_MKDIR_P])dnl
|
||||||
|
# For better backward compatibility. To be removed once Automake 1.9.x
|
||||||
|
# dies out for good. For more background, see:
|
||||||
|
# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
|
||||||
|
# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
|
||||||
|
AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
|
||||||
|
# We need awk for the "check" target (and possibly the TAP driver). The
|
||||||
|
# system "awk" is bad on some platforms.
|
||||||
|
AC_REQUIRE([AC_PROG_AWK])dnl
|
||||||
|
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
|
||||||
|
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
|
||||||
|
_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
|
||||||
|
[_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
|
||||||
|
[_AM_PROG_TAR([v7])])])
|
||||||
|
_AM_IF_OPTION([no-dependencies],,
|
||||||
|
[AC_PROVIDE_IFELSE([AC_PROG_CC],
|
||||||
|
[_AM_DEPENDENCIES([CC])],
|
||||||
|
[m4_define([AC_PROG_CC],
|
||||||
|
m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
|
||||||
|
AC_PROVIDE_IFELSE([AC_PROG_CXX],
|
||||||
|
[_AM_DEPENDENCIES([CXX])],
|
||||||
|
[m4_define([AC_PROG_CXX],
|
||||||
|
m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
|
||||||
|
AC_PROVIDE_IFELSE([AC_PROG_OBJC],
|
||||||
|
[_AM_DEPENDENCIES([OBJC])],
|
||||||
|
[m4_define([AC_PROG_OBJC],
|
||||||
|
m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
|
||||||
|
AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
|
||||||
|
[_AM_DEPENDENCIES([OBJCXX])],
|
||||||
|
[m4_define([AC_PROG_OBJCXX],
|
||||||
|
m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
|
||||||
|
])
|
||||||
|
# Variables for tags utilities; see am/tags.am
|
||||||
|
if test -z "$CTAGS"; then
|
||||||
|
CTAGS=ctags
|
||||||
|
fi
|
||||||
|
AC_SUBST([CTAGS])
|
||||||
|
if test -z "$ETAGS"; then
|
||||||
|
ETAGS=etags
|
||||||
|
fi
|
||||||
|
AC_SUBST([ETAGS])
|
||||||
|
if test -z "$CSCOPE"; then
|
||||||
|
CSCOPE=cscope
|
||||||
|
fi
|
||||||
|
AC_SUBST([CSCOPE])
|
||||||
|
|
||||||
|
AC_REQUIRE([_AM_SILENT_RULES])dnl
|
||||||
|
dnl The testsuite driver may need to know about EXEEXT, so add the
|
||||||
|
dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
|
||||||
|
dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
|
||||||
|
AC_CONFIG_COMMANDS_PRE(dnl
|
||||||
|
[m4_provide_if([_AM_COMPILER_EXEEXT],
|
||||||
|
[AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
|
||||||
|
|
||||||
|
AC_REQUIRE([_AM_PROG_RM_F])
|
||||||
|
AC_REQUIRE([_AM_PROG_XARGS_N])
|
||||||
|
|
||||||
|
dnl The trailing newline in this macro's definition is deliberate, for
|
||||||
|
dnl backward compatibility and to allow trailing 'dnl'-style comments
|
||||||
|
dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
|
||||||
|
dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
|
||||||
|
dnl mangled by Autoconf and run in a shell conditional statement.
|
||||||
|
m4_define([_AC_COMPILER_EXEEXT],
|
||||||
|
m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
|
||||||
|
|
||||||
|
# When config.status generates a header, we must update the stamp-h file.
|
||||||
|
# This file resides in the same directory as the config header
|
||||||
|
# that is generated. The stamp files are numbered to have different names.
|
||||||
|
|
||||||
|
# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
|
||||||
|
# loop where config.status creates the headers, so we can generate
|
||||||
|
# our stamp files there.
|
||||||
|
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
|
||||||
|
[# Compute $1's index in $config_headers.
|
||||||
|
_am_arg=$1
|
||||||
|
_am_stamp_count=1
|
||||||
|
for _am_header in $config_headers :; do
|
||||||
|
case $_am_header in
|
||||||
|
$_am_arg | $_am_arg:* )
|
||||||
|
break ;;
|
||||||
|
* )
|
||||||
|
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
|
||||||
|
|
||||||
|
# Copyright (C) 2001-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# AM_PROG_INSTALL_SH
|
||||||
|
# ------------------
|
||||||
|
# Define $install_sh.
|
||||||
|
AC_DEFUN([AM_PROG_INSTALL_SH],
|
||||||
|
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||||
|
if test x"${install_sh+set}" != xset; then
|
||||||
|
case $am_aux_dir in
|
||||||
|
*\ * | *\ *)
|
||||||
|
install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
|
||||||
|
*)
|
||||||
|
install_sh="\${SHELL} $am_aux_dir/install-sh"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
AC_SUBST([install_sh])])
|
||||||
|
|
||||||
|
# Copyright (C) 2003-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# Check whether the underlying file-system supports filenames
|
||||||
|
# with a leading dot. For instance MS-DOS doesn't.
|
||||||
|
AC_DEFUN([AM_SET_LEADING_DOT],
|
||||||
|
[rm -rf .tst 2>/dev/null
|
||||||
|
mkdir .tst 2>/dev/null
|
||||||
|
if test -d .tst; then
|
||||||
|
am__leading_dot=.
|
||||||
|
else
|
||||||
|
am__leading_dot=_
|
||||||
|
fi
|
||||||
|
rmdir .tst 2>/dev/null
|
||||||
|
AC_SUBST([am__leading_dot])])
|
||||||
|
|
||||||
|
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
|
||||||
|
|
||||||
|
# Copyright (C) 1997-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# AM_MISSING_PROG(NAME, PROGRAM)
|
||||||
|
# ------------------------------
|
||||||
|
AC_DEFUN([AM_MISSING_PROG],
|
||||||
|
[AC_REQUIRE([AM_MISSING_HAS_RUN])
|
||||||
|
$1=${$1-"${am_missing_run}$2"}
|
||||||
|
AC_SUBST($1)])
|
||||||
|
|
||||||
|
# AM_MISSING_HAS_RUN
|
||||||
|
# ------------------
|
||||||
|
# Define MISSING if not defined so far and test if it is modern enough.
|
||||||
|
# If it is, set am_missing_run to use it, otherwise, to nothing.
|
||||||
|
AC_DEFUN([AM_MISSING_HAS_RUN],
|
||||||
|
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||||
|
AC_REQUIRE_AUX_FILE([missing])dnl
|
||||||
|
if test x"${MISSING+set}" != xset; then
|
||||||
|
MISSING="\${SHELL} '$am_aux_dir/missing'"
|
||||||
|
fi
|
||||||
|
# Use eval to expand $SHELL
|
||||||
|
if eval "$MISSING --is-lightweight"; then
|
||||||
|
am_missing_run="$MISSING "
|
||||||
|
else
|
||||||
|
am_missing_run=
|
||||||
|
AC_MSG_WARN(['missing' script is too old or missing])
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
# Helper functions for option handling. -*- Autoconf -*-
|
||||||
|
|
||||||
|
# Copyright (C) 2001-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# _AM_MANGLE_OPTION(NAME)
|
||||||
|
# -----------------------
|
||||||
|
AC_DEFUN([_AM_MANGLE_OPTION],
|
||||||
|
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
|
||||||
|
|
||||||
|
# _AM_SET_OPTION(NAME)
|
||||||
|
# --------------------
|
||||||
|
# Set option NAME. Presently that only means defining a flag for this option.
|
||||||
|
AC_DEFUN([_AM_SET_OPTION],
|
||||||
|
[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
|
||||||
|
|
||||||
|
# _AM_SET_OPTIONS(OPTIONS)
|
||||||
|
# ------------------------
|
||||||
|
# OPTIONS is a space-separated list of Automake options.
|
||||||
|
AC_DEFUN([_AM_SET_OPTIONS],
|
||||||
|
[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
|
||||||
|
|
||||||
|
# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
|
||||||
|
# -------------------------------------------
|
||||||
|
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
||||||
|
AC_DEFUN([_AM_IF_OPTION],
|
||||||
|
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
|
||||||
|
|
||||||
|
# Copyright (C) 2022-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# _AM_PROG_RM_F
|
||||||
|
# ---------------
|
||||||
|
# Check whether 'rm -f' without any arguments works.
|
||||||
|
# https://bugs.gnu.org/10828
|
||||||
|
AC_DEFUN([_AM_PROG_RM_F],
|
||||||
|
[am__rm_f_notfound=
|
||||||
|
AS_IF([(rm -f && rm -fr && rm -rf) 2>/dev/null], [], [am__rm_f_notfound='""'])
|
||||||
|
AC_SUBST(am__rm_f_notfound)
|
||||||
|
])
|
||||||
|
|
||||||
|
# Copyright (C) 2001-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# AM_RUN_LOG(COMMAND)
|
||||||
|
# -------------------
|
||||||
|
# Run COMMAND, save the exit status in ac_status, and log it.
|
||||||
|
# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
|
||||||
|
AC_DEFUN([AM_RUN_LOG],
|
||||||
|
[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
|
||||||
|
($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
|
||||||
|
ac_status=$?
|
||||||
|
echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
|
||||||
|
(exit $ac_status); }])
|
||||||
|
|
||||||
|
# Check to make sure that the build environment is sane. -*- Autoconf -*-
|
||||||
|
|
||||||
|
# Copyright (C) 1996-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# _AM_SLEEP_FRACTIONAL_SECONDS
|
||||||
|
# ----------------------------
|
||||||
|
AC_DEFUN([_AM_SLEEP_FRACTIONAL_SECONDS], [dnl
|
||||||
|
AC_CACHE_CHECK([whether sleep supports fractional seconds],
|
||||||
|
am_cv_sleep_fractional_seconds, [dnl
|
||||||
|
AS_IF([sleep 0.001 2>/dev/null], [am_cv_sleep_fractional_seconds=yes],
|
||||||
|
[am_cv_sleep_fractional_seconds=no])
|
||||||
|
])])
|
||||||
|
|
||||||
|
# _AM_FILESYSTEM_TIMESTAMP_RESOLUTION
|
||||||
|
# -----------------------------------
|
||||||
|
# Determine the filesystem's resolution for file modification
|
||||||
|
# timestamps. The coarsest we know of is FAT, with a resolution
|
||||||
|
# of only two seconds, even with the most recent "exFAT" extensions.
|
||||||
|
# The finest (e.g. ext4 with large inodes, XFS, ZFS) is one
|
||||||
|
# nanosecond, matching clock_gettime. However, it is probably not
|
||||||
|
# possible to delay execution of a shell script for less than one
|
||||||
|
# millisecond, due to process creation overhead and scheduling
|
||||||
|
# granularity, so we don't check for anything finer than that. (See below.)
|
||||||
|
AC_DEFUN([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION], [dnl
|
||||||
|
AC_REQUIRE([_AM_SLEEP_FRACTIONAL_SECONDS])
|
||||||
|
AC_CACHE_CHECK([filesystem timestamp resolution],
|
||||||
|
am_cv_filesystem_timestamp_resolution, [dnl
|
||||||
|
# Default to the worst case.
|
||||||
|
am_cv_filesystem_timestamp_resolution=2
|
||||||
|
|
||||||
|
# Only try to go finer than 1 sec if sleep can do it.
|
||||||
|
# Don't try 1 sec, because if 0.01 sec and 0.1 sec don't work,
|
||||||
|
# - 1 sec is not much of a win compared to 2 sec, and
|
||||||
|
# - it takes 2 seconds to perform the test whether 1 sec works.
|
||||||
|
#
|
||||||
|
# Instead, just use the default 2s on platforms that have 1s resolution,
|
||||||
|
# accept the extra 1s delay when using $sleep in the Automake tests, in
|
||||||
|
# exchange for not incurring the 2s delay for running the test for all
|
||||||
|
# packages.
|
||||||
|
#
|
||||||
|
am_try_resolutions=
|
||||||
|
if test "$am_cv_sleep_fractional_seconds" = yes; then
|
||||||
|
# Even a millisecond often causes a bunch of false positives,
|
||||||
|
# so just try a hundredth of a second. The time saved between .001 and
|
||||||
|
# .01 is not terribly consequential.
|
||||||
|
am_try_resolutions="0.01 0.1 $am_try_resolutions"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# In order to catch current-generation FAT out, we must *modify* files
|
||||||
|
# that already exist; the *creation* timestamp is finer. Use names
|
||||||
|
# that make ls -t sort them differently when they have equal
|
||||||
|
# timestamps than when they have distinct timestamps, keeping
|
||||||
|
# in mind that ls -t prints the *newest* file first.
|
||||||
|
rm -f conftest.ts?
|
||||||
|
: > conftest.ts1
|
||||||
|
: > conftest.ts2
|
||||||
|
: > conftest.ts3
|
||||||
|
|
||||||
|
# Make sure ls -t actually works. Do 'set' in a subshell so we don't
|
||||||
|
# clobber the current shell's arguments. (Outer-level square brackets
|
||||||
|
# are removed by m4; they're present so that m4 does not expand
|
||||||
|
# <dollar><star>; be careful, easy to get confused.)
|
||||||
|
if (
|
||||||
|
set X `[ls -t conftest.ts[12]]` &&
|
||||||
|
{
|
||||||
|
test "$[]*" != "X conftest.ts1 conftest.ts2" ||
|
||||||
|
test "$[]*" != "X conftest.ts2 conftest.ts1";
|
||||||
|
}
|
||||||
|
); then :; else
|
||||||
|
# If neither matched, then we have a broken ls. This can happen
|
||||||
|
# if, for instance, CONFIG_SHELL is bash and it inherits a
|
||||||
|
# broken ls alias from the environment. This has actually
|
||||||
|
# happened. Such a system could not be considered "sane".
|
||||||
|
_AS_ECHO_UNQUOTED(
|
||||||
|
["Bad output from ls -t: \"`[ls -t conftest.ts[12]]`\""],
|
||||||
|
[AS_MESSAGE_LOG_FD])
|
||||||
|
AC_MSG_FAILURE([ls -t produces unexpected output.
|
||||||
|
Make sure there is not a broken ls alias in your environment.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
for am_try_res in $am_try_resolutions; do
|
||||||
|
# Any one fine-grained sleep might happen to cross the boundary
|
||||||
|
# between two values of a coarser actual resolution, but if we do
|
||||||
|
# two fine-grained sleeps in a row, at least one of them will fall
|
||||||
|
# entirely within a coarse interval.
|
||||||
|
echo alpha > conftest.ts1
|
||||||
|
sleep $am_try_res
|
||||||
|
echo beta > conftest.ts2
|
||||||
|
sleep $am_try_res
|
||||||
|
echo gamma > conftest.ts3
|
||||||
|
|
||||||
|
# We assume that 'ls -t' will make use of high-resolution
|
||||||
|
# timestamps if the operating system supports them at all.
|
||||||
|
if (set X `ls -t conftest.ts?` &&
|
||||||
|
test "$[]2" = conftest.ts3 &&
|
||||||
|
test "$[]3" = conftest.ts2 &&
|
||||||
|
test "$[]4" = conftest.ts1); then
|
||||||
|
#
|
||||||
|
# Ok, ls -t worked. If we're at a resolution of 1 second, we're done,
|
||||||
|
# because we don't need to test make.
|
||||||
|
make_ok=true
|
||||||
|
if test $am_try_res != 1; then
|
||||||
|
# But if we've succeeded so far with a subsecond resolution, we
|
||||||
|
# have one more thing to check: make. It can happen that
|
||||||
|
# everything else supports the subsecond mtimes, but make doesn't;
|
||||||
|
# notably on macOS, which ships make 3.81 from 2006 (the last one
|
||||||
|
# released under GPLv2). https://bugs.gnu.org/68808
|
||||||
|
#
|
||||||
|
# We test $MAKE if it is defined in the environment, else "make".
|
||||||
|
# It might get overridden later, but our hope is that in practice
|
||||||
|
# it does not matter: it is the system "make" which is (by far)
|
||||||
|
# the most likely to be broken, whereas if the user overrides it,
|
||||||
|
# probably they did so with a better, or at least not worse, make.
|
||||||
|
# https://lists.gnu.org/archive/html/automake/2024-06/msg00051.html
|
||||||
|
#
|
||||||
|
# Create a Makefile (real tab character here):
|
||||||
|
rm -f conftest.mk
|
||||||
|
echo 'conftest.ts1: conftest.ts2' >conftest.mk
|
||||||
|
echo ' touch conftest.ts2' >>conftest.mk
|
||||||
|
#
|
||||||
|
# Now, running
|
||||||
|
# touch conftest.ts1; touch conftest.ts2; make
|
||||||
|
# should touch ts1 because ts2 is newer. This could happen by luck,
|
||||||
|
# but most often, it will fail if make's support is insufficient. So
|
||||||
|
# test for several consecutive successes.
|
||||||
|
#
|
||||||
|
# (We reuse conftest.ts[12] because we still want to modify existing
|
||||||
|
# files, not create new ones, per above.)
|
||||||
|
n=0
|
||||||
|
make=${MAKE-make}
|
||||||
|
until test $n -eq 3; do
|
||||||
|
echo one > conftest.ts1
|
||||||
|
sleep $am_try_res
|
||||||
|
echo two > conftest.ts2 # ts2 should now be newer than ts1
|
||||||
|
if $make -f conftest.mk | grep 'up to date' >/dev/null; then
|
||||||
|
make_ok=false
|
||||||
|
break # out of $n loop
|
||||||
|
fi
|
||||||
|
n=`expr $n + 1`
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
#
|
||||||
|
if $make_ok; then
|
||||||
|
# Everything we know to check worked out, so call this resolution good.
|
||||||
|
am_cv_filesystem_timestamp_resolution=$am_try_res
|
||||||
|
break # out of $am_try_res loop
|
||||||
|
fi
|
||||||
|
# Otherwise, we'll go on to check the next resolution.
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
rm -f conftest.ts?
|
||||||
|
# (end _am_filesystem_timestamp_resolution)
|
||||||
|
])])
|
||||||
|
|
||||||
|
# AM_SANITY_CHECK
|
||||||
|
# ---------------
|
||||||
|
AC_DEFUN([AM_SANITY_CHECK],
|
||||||
|
[AC_REQUIRE([_AM_FILESYSTEM_TIMESTAMP_RESOLUTION])
|
||||||
|
# This check should not be cached, as it may vary across builds of
|
||||||
|
# different projects.
|
||||||
|
AC_MSG_CHECKING([whether build environment is sane])
|
||||||
|
# Reject unsafe characters in $srcdir or the absolute working directory
|
||||||
|
# name. Accept space and tab only in the latter.
|
||||||
|
am_lf='
|
||||||
|
'
|
||||||
|
case `pwd` in
|
||||||
|
*[[\\\"\#\$\&\'\`$am_lf]]*)
|
||||||
|
AC_MSG_ERROR([unsafe absolute working directory name]);;
|
||||||
|
esac
|
||||||
|
case $srcdir in
|
||||||
|
*[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
|
||||||
|
AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Do 'set' in a subshell so we don't clobber the current shell's
|
||||||
|
# arguments. Must try -L first in case configure is actually a
|
||||||
|
# symlink; some systems play weird games with the mod time of symlinks
|
||||||
|
# (eg FreeBSD returns the mod time of the symlink's containing
|
||||||
|
# directory).
|
||||||
|
am_build_env_is_sane=no
|
||||||
|
am_has_slept=no
|
||||||
|
rm -f conftest.file
|
||||||
|
for am_try in 1 2; do
|
||||||
|
echo "timestamp, slept: $am_has_slept" > conftest.file
|
||||||
|
if (
|
||||||
|
set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
|
||||||
|
if test "$[]*" = "X"; then
|
||||||
|
# -L didn't work.
|
||||||
|
set X `ls -t "$srcdir/configure" conftest.file`
|
||||||
|
fi
|
||||||
|
test "$[]2" = conftest.file
|
||||||
|
); then
|
||||||
|
am_build_env_is_sane=yes
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
# Just in case.
|
||||||
|
sleep "$am_cv_filesystem_timestamp_resolution"
|
||||||
|
am_has_slept=yes
|
||||||
|
done
|
||||||
|
|
||||||
|
AC_MSG_RESULT([$am_build_env_is_sane])
|
||||||
|
if test "$am_build_env_is_sane" = no; then
|
||||||
|
AC_MSG_ERROR([newly created file is older than distributed files!
|
||||||
|
Check your system clock])
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If we didn't sleep, we still need to ensure time stamps of config.status and
|
||||||
|
# generated files are strictly newer.
|
||||||
|
am_sleep_pid=
|
||||||
|
AS_IF([test -e conftest.file || grep 'slept: no' conftest.file >/dev/null 2>&1],, [dnl
|
||||||
|
( sleep "$am_cv_filesystem_timestamp_resolution" ) &
|
||||||
|
am_sleep_pid=$!
|
||||||
|
])
|
||||||
|
AC_CONFIG_COMMANDS_PRE(
|
||||||
|
[AC_MSG_CHECKING([that generated files are newer than configure])
|
||||||
|
if test -n "$am_sleep_pid"; then
|
||||||
|
# Hide warnings about reused PIDs.
|
||||||
|
wait $am_sleep_pid 2>/dev/null
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT([done])])
|
||||||
|
rm -f conftest.file
|
||||||
|
])
|
||||||
|
|
||||||
|
# Copyright (C) 2009-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# _AM_SILENT_RULES
|
||||||
|
# ----------------
|
||||||
|
# Enable less verbose build rules support.
|
||||||
|
AC_DEFUN([_AM_SILENT_RULES],
|
||||||
|
[AM_DEFAULT_VERBOSITY=1
|
||||||
|
AC_ARG_ENABLE([silent-rules], [dnl
|
||||||
|
AS_HELP_STRING(
|
||||||
|
[--enable-silent-rules],
|
||||||
|
[less verbose build output (undo: "make V=1")])
|
||||||
|
AS_HELP_STRING(
|
||||||
|
[--disable-silent-rules],
|
||||||
|
[verbose build output (undo: "make V=0")])dnl
|
||||||
|
])
|
||||||
|
dnl
|
||||||
|
dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
|
||||||
|
dnl do not support nested variable expansions.
|
||||||
|
dnl See automake bug#9928 and bug#10237.
|
||||||
|
am_make=${MAKE-make}
|
||||||
|
AC_CACHE_CHECK([whether $am_make supports nested variables],
|
||||||
|
[am_cv_make_support_nested_variables],
|
||||||
|
[if AS_ECHO([['TRUE=$(BAR$(V))
|
||||||
|
BAR0=false
|
||||||
|
BAR1=true
|
||||||
|
V=1
|
||||||
|
am__doit:
|
||||||
|
@$(TRUE)
|
||||||
|
.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
|
||||||
|
am_cv_make_support_nested_variables=yes
|
||||||
|
else
|
||||||
|
am_cv_make_support_nested_variables=no
|
||||||
|
fi])
|
||||||
|
AC_SUBST([AM_V])dnl
|
||||||
|
AM_SUBST_NOTMAKE([AM_V])dnl
|
||||||
|
AC_SUBST([AM_DEFAULT_V])dnl
|
||||||
|
AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
|
||||||
|
AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
|
||||||
|
AM_BACKSLASH='\'
|
||||||
|
AC_SUBST([AM_BACKSLASH])dnl
|
||||||
|
_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
|
||||||
|
dnl Delay evaluation of AM_DEFAULT_VERBOSITY to the end to allow multiple calls
|
||||||
|
dnl to AM_SILENT_RULES to change the default value.
|
||||||
|
AC_CONFIG_COMMANDS_PRE([dnl
|
||||||
|
case $enable_silent_rules in @%:@ (((
|
||||||
|
yes) AM_DEFAULT_VERBOSITY=0;;
|
||||||
|
no) AM_DEFAULT_VERBOSITY=1;;
|
||||||
|
esac
|
||||||
|
if test $am_cv_make_support_nested_variables = yes; then
|
||||||
|
dnl Using '$V' instead of '$(V)' breaks IRIX make.
|
||||||
|
AM_V='$(V)'
|
||||||
|
AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
|
||||||
|
else
|
||||||
|
AM_V=$AM_DEFAULT_VERBOSITY
|
||||||
|
AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
|
||||||
|
fi
|
||||||
|
])dnl
|
||||||
|
])
|
||||||
|
|
||||||
|
# AM_SILENT_RULES([DEFAULT])
|
||||||
|
# --------------------------
|
||||||
|
# Set the default verbosity level to DEFAULT ("yes" being less verbose, "no" or
|
||||||
|
# empty being verbose).
|
||||||
|
AC_DEFUN([AM_SILENT_RULES],
|
||||||
|
[AC_REQUIRE([_AM_SILENT_RULES])
|
||||||
|
AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1])])
|
||||||
|
|
||||||
|
# Copyright (C) 2001-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# AM_PROG_INSTALL_STRIP
|
||||||
|
# ---------------------
|
||||||
|
# One issue with vendor 'install' (even GNU) is that you can't
|
||||||
|
# specify the program used to strip binaries. This is especially
|
||||||
|
# annoying in cross-compiling environments, where the build's strip
|
||||||
|
# is unlikely to handle the host's binaries.
|
||||||
|
# Fortunately install-sh will honor a STRIPPROG variable, so we
|
||||||
|
# always use install-sh in "make install-strip", and initialize
|
||||||
|
# STRIPPROG with the value of the STRIP variable (set by the user).
|
||||||
|
AC_DEFUN([AM_PROG_INSTALL_STRIP],
|
||||||
|
[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
|
||||||
|
# Installed binaries are usually stripped using 'strip' when the user
|
||||||
|
# run "make install-strip". However 'strip' might not be the right
|
||||||
|
# tool to use in cross-compilation environments, therefore Automake
|
||||||
|
# will honor the 'STRIP' environment variable to overrule this program.
|
||||||
|
dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
|
||||||
|
if test "$cross_compiling" != no; then
|
||||||
|
AC_CHECK_TOOL([STRIP], [strip], :)
|
||||||
|
fi
|
||||||
|
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
|
||||||
|
AC_SUBST([INSTALL_STRIP_PROGRAM])])
|
||||||
|
|
||||||
|
# Copyright (C) 2006-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# _AM_SUBST_NOTMAKE(VARIABLE)
|
||||||
|
# ---------------------------
|
||||||
|
# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
|
||||||
|
# This macro is traced by Automake.
|
||||||
|
AC_DEFUN([_AM_SUBST_NOTMAKE])
|
||||||
|
|
||||||
|
# AM_SUBST_NOTMAKE(VARIABLE)
|
||||||
|
# --------------------------
|
||||||
|
# Public sister of _AM_SUBST_NOTMAKE.
|
||||||
|
AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
|
||||||
|
|
||||||
|
# Check how to create a tarball. -*- Autoconf -*-
|
||||||
|
|
||||||
|
# Copyright (C) 2004-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# _AM_PROG_TAR(FORMAT)
|
||||||
|
# --------------------
|
||||||
|
# Check how to create a tarball in format FORMAT.
|
||||||
|
# FORMAT should be one of 'v7', 'ustar', or 'pax'.
|
||||||
|
#
|
||||||
|
# Substitute a variable $(am__tar) that is a command
|
||||||
|
# writing to stdout a FORMAT-tarball containing the directory
|
||||||
|
# $tardir.
|
||||||
|
# tardir=directory && $(am__tar) > result.tar
|
||||||
|
#
|
||||||
|
# Substitute a variable $(am__untar) that extract such
|
||||||
|
# a tarball read from stdin.
|
||||||
|
# $(am__untar) < result.tar
|
||||||
|
#
|
||||||
|
AC_DEFUN([_AM_PROG_TAR],
|
||||||
|
[# Always define AMTAR for backward compatibility. Yes, it's still used
|
||||||
|
# in the wild :-( We should find a proper way to deprecate it ...
|
||||||
|
AC_SUBST([AMTAR], ['$${TAR-tar}'])
|
||||||
|
|
||||||
|
# We'll loop over all known methods to create a tar archive until one works.
|
||||||
|
_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
|
||||||
|
|
||||||
|
m4_if([$1], [v7],
|
||||||
|
[am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
|
||||||
|
|
||||||
|
[m4_case([$1],
|
||||||
|
[ustar],
|
||||||
|
[# The POSIX 1988 'ustar' format is defined with fixed-size fields.
|
||||||
|
# There is notably a 21 bits limit for the UID and the GID. In fact,
|
||||||
|
# the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
|
||||||
|
# and bug#13588).
|
||||||
|
am_max_uid=2097151 # 2^21 - 1
|
||||||
|
am_max_gid=$am_max_uid
|
||||||
|
# The $UID and $GID variables are not portable, so we need to resort
|
||||||
|
# to the POSIX-mandated id(1) utility. Errors in the 'id' calls
|
||||||
|
# below are definitely unexpected, so allow the users to see them
|
||||||
|
# (that is, avoid stderr redirection).
|
||||||
|
am_uid=`id -u || echo unknown`
|
||||||
|
am_gid=`id -g || echo unknown`
|
||||||
|
AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
|
||||||
|
if test x$am_uid = xunknown; then
|
||||||
|
AC_MSG_WARN([ancient id detected; assuming current UID is ok, but dist-ustar might not work])
|
||||||
|
elif test $am_uid -le $am_max_uid; then
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
_am_tools=none
|
||||||
|
fi
|
||||||
|
AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
|
||||||
|
if test x$gm_gid = xunknown; then
|
||||||
|
AC_MSG_WARN([ancient id detected; assuming current GID is ok, but dist-ustar might not work])
|
||||||
|
elif test $am_gid -le $am_max_gid; then
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
_am_tools=none
|
||||||
|
fi],
|
||||||
|
|
||||||
|
[pax],
|
||||||
|
[],
|
||||||
|
|
||||||
|
[m4_fatal([Unknown tar format])])
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([how to create a $1 tar archive])
|
||||||
|
|
||||||
|
# Go ahead even if we have the value already cached. We do so because we
|
||||||
|
# need to set the values for the 'am__tar' and 'am__untar' variables.
|
||||||
|
_am_tools=${am_cv_prog_tar_$1-$_am_tools}
|
||||||
|
|
||||||
|
for _am_tool in $_am_tools; do
|
||||||
|
case $_am_tool in
|
||||||
|
gnutar)
|
||||||
|
for _am_tar in tar gnutar gtar; do
|
||||||
|
AM_RUN_LOG([$_am_tar --version]) && break
|
||||||
|
done
|
||||||
|
am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
|
||||||
|
am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
|
||||||
|
am__untar="$_am_tar -xf -"
|
||||||
|
;;
|
||||||
|
plaintar)
|
||||||
|
# Must skip GNU tar: if it does not support --format= it doesn't create
|
||||||
|
# ustar tarball either.
|
||||||
|
(tar --version) >/dev/null 2>&1 && continue
|
||||||
|
am__tar='tar chf - "$$tardir"'
|
||||||
|
am__tar_='tar chf - "$tardir"'
|
||||||
|
am__untar='tar xf -'
|
||||||
|
;;
|
||||||
|
pax)
|
||||||
|
am__tar='pax -L -x $1 -w "$$tardir"'
|
||||||
|
am__tar_='pax -L -x $1 -w "$tardir"'
|
||||||
|
am__untar='pax -r'
|
||||||
|
;;
|
||||||
|
cpio)
|
||||||
|
am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
|
||||||
|
am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
|
||||||
|
am__untar='cpio -i -H $1 -d'
|
||||||
|
;;
|
||||||
|
none)
|
||||||
|
am__tar=false
|
||||||
|
am__tar_=false
|
||||||
|
am__untar=false
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# If the value was cached, stop now. We just wanted to have am__tar
|
||||||
|
# and am__untar set.
|
||||||
|
test -n "${am_cv_prog_tar_$1}" && break
|
||||||
|
|
||||||
|
# tar/untar a dummy directory, and stop if the command works.
|
||||||
|
rm -rf conftest.dir
|
||||||
|
mkdir conftest.dir
|
||||||
|
echo GrepMe > conftest.dir/file
|
||||||
|
AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
|
||||||
|
rm -rf conftest.dir
|
||||||
|
if test -s conftest.tar; then
|
||||||
|
AM_RUN_LOG([$am__untar <conftest.tar])
|
||||||
|
AM_RUN_LOG([cat conftest.dir/file])
|
||||||
|
grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
rm -rf conftest.dir
|
||||||
|
|
||||||
|
AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
|
||||||
|
AC_MSG_RESULT([$am_cv_prog_tar_$1])])
|
||||||
|
|
||||||
|
AC_SUBST([am__tar])
|
||||||
|
AC_SUBST([am__untar])
|
||||||
|
]) # _AM_PROG_TAR
|
||||||
|
|
||||||
|
# Copyright (C) 2022-2024 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is free software; the Free Software Foundation
|
||||||
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
# _AM_PROG_XARGS_N
|
||||||
|
# ----------------
|
||||||
|
# Check whether 'xargs -n' works. It should work everywhere, so the fallback
|
||||||
|
# is not optimized at all as we never expect to use it.
|
||||||
|
AC_DEFUN([_AM_PROG_XARGS_N],
|
||||||
|
[AC_CACHE_CHECK([xargs -n works], am_cv_xargs_n_works, [dnl
|
||||||
|
AS_IF([test "`echo 1 2 3 | xargs -n2 echo`" = "1 2
|
||||||
|
3"], [am_cv_xargs_n_works=yes], [am_cv_xargs_n_works=no])])
|
||||||
|
AS_IF([test "$am_cv_xargs_n_works" = yes], [am__xargs_n='xargs -n'], [dnl
|
||||||
|
am__xargs_n='am__xargs_n () { shift; sed "s/ /\\n/g" | while read am__xargs_n_arg; do "$@" "$am__xargs_n_arg"; done; }'
|
||||||
|
])dnl
|
||||||
|
AC_SUBST(am__xargs_n)
|
||||||
|
])
|
||||||
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package accoper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"mbase/pkg/auxpwd"
|
||||||
|
"mbase/pkg/auxtool"
|
||||||
|
"mbase/pkg/auxuuid"
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateAccountParams struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
type CreateAccountResult struct {
|
||||||
|
AccountID string `json:"accountId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oper *Operator) CreateAccount(ctx context.Context, operatorID string, params *CreateAccountParams) (*CreateAccountResult, error) {
|
||||||
|
var err error
|
||||||
|
res := &CreateAccountResult{}
|
||||||
|
|
||||||
|
if params.Username == "" {
|
||||||
|
err := fmt.Errorf("Empty username parameters")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Password == "" {
|
||||||
|
err := fmt.Errorf("Empty password parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
accountExists, _, err := oper.mdb.GetAccountByUsername(ctx, params.Username)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if accountExists {
|
||||||
|
err := fmt.Errorf("Account with thist name already exists")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
now := auxtool.TimeNow()
|
||||||
|
passhash := auxpwd.MakeSHA256Hash([]byte(params.Password))
|
||||||
|
accountDescr := &descr.Account{
|
||||||
|
ID: auxuuid.NewUUID(),
|
||||||
|
Username: params.Username,
|
||||||
|
Passhash: passhash,
|
||||||
|
Disabled: false,
|
||||||
|
CreatedAt: now,
|
||||||
|
UpdatedAt: now,
|
||||||
|
CreatedBy: operatorID,
|
||||||
|
UpdatedBy: operatorID,
|
||||||
|
}
|
||||||
|
err = oper.mdb.InsertAccount(ctx, accountDescr)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
res.AccountID = accountDescr.ID
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package accoper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"mbase/pkg/auxtool"
|
||||||
|
"mbase/pkg/auxuuid"
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateGrant
|
||||||
|
type CreateGrantParams struct {
|
||||||
|
AccountID string `json:"accountID"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Right string `json:"operation"`
|
||||||
|
Pattern string `json:"pattern"`
|
||||||
|
}
|
||||||
|
type CreateGrantResult struct {
|
||||||
|
GrantID string `json:"grantId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oper *Operator) CreateGrant(ctx context.Context, operatorID string, params *CreateGrantParams) (*CreateGrantResult, error) {
|
||||||
|
var err error
|
||||||
|
res := &CreateGrantResult{}
|
||||||
|
|
||||||
|
if params.AccountID == "" {
|
||||||
|
err := fmt.Errorf("Empty accountId parameters")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if params.Right == "" {
|
||||||
|
err := fmt.Errorf("Empty operation parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if params.Pattern == "" {
|
||||||
|
err := fmt.Errorf("Empty pattern parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = regexp.Compile(params.Pattern)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Cannot compile regexp %s: %v", err)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var accountDescr *descr.Account
|
||||||
|
var accountExists bool
|
||||||
|
switch {
|
||||||
|
case params.AccountID != "":
|
||||||
|
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !accountExists {
|
||||||
|
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
case params.Username != "":
|
||||||
|
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !accountExists {
|
||||||
|
err := fmt.Errorf("Account with name %s dont exists", params.Username)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err := fmt.Errorf("Empty username and accountId parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
grantExists, _, err := oper.mdb.GetGrantByAccoundIDRightPattern(ctx, params.AccountID, params.Right, params.Pattern)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if grantExists {
|
||||||
|
err := fmt.Errorf("Grant with this right already exists")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
now := auxtool.TimeNow()
|
||||||
|
grantDescr := &descr.Grant{
|
||||||
|
ID: auxuuid.NewUUID(),
|
||||||
|
AccountID: accountDescr.ID,
|
||||||
|
Right: params.Right,
|
||||||
|
Pattern: params.Pattern,
|
||||||
|
CreatedAt: now,
|
||||||
|
UpdatedAt: now,
|
||||||
|
CreatedBy: operatorID,
|
||||||
|
UpdatedBy: operatorID,
|
||||||
|
}
|
||||||
|
err = oper.mdb.InsertGrant(ctx, grantDescr)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
res.GrantID = grantDescr.ID
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package accoper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeleteAccountParams struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
AccountID string `json:"accountId"`
|
||||||
|
}
|
||||||
|
type DeleteAccountResult struct{}
|
||||||
|
|
||||||
|
func (oper *Operator) DeleteAccount(ctx context.Context, operatorID string, params *DeleteAccountParams) (*DeleteAccountResult, error) {
|
||||||
|
var err error
|
||||||
|
res := &DeleteAccountResult{}
|
||||||
|
|
||||||
|
if params.Username == "" && params.AccountID == "" {
|
||||||
|
err := fmt.Errorf("Empty username and accountId parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var accountDescr *descr.Account
|
||||||
|
var accountExists bool
|
||||||
|
switch {
|
||||||
|
case params.AccountID != "":
|
||||||
|
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !accountExists {
|
||||||
|
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
case params.Username != "":
|
||||||
|
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !accountExists {
|
||||||
|
err := fmt.Errorf("Account with name %s dont exists", params.Username)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err := fmt.Errorf("Empty username and accountId parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if accountDescr == nil {
|
||||||
|
err := fmt.Errorf("Null account desriptor")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
err = oper.mdb.DeleteAllGrantsForAccountID(ctx, accountDescr.ID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
err = oper.mdb.DeleteAccountByID(ctx, accountDescr.ID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package accoper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeleteGrant
|
||||||
|
type DeleteGrantParams struct {
|
||||||
|
GrantID string `json:"grantId"`
|
||||||
|
}
|
||||||
|
type DeleteGrantResult struct{}
|
||||||
|
|
||||||
|
func (oper *Operator) DeleteGrant(ctx context.Context, operatorID string, params *DeleteGrantParams) (*DeleteGrantResult, error) {
|
||||||
|
var err error
|
||||||
|
res := &DeleteGrantResult{}
|
||||||
|
|
||||||
|
if params.GrantID == "" {
|
||||||
|
err := fmt.Errorf("Empty grantId parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var grantDescr *descr.Grant
|
||||||
|
var grantExists bool
|
||||||
|
|
||||||
|
grantExists, grantDescr, err = oper.mdb.GetGrantByID(ctx, params.GrantID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !grantExists {
|
||||||
|
err := fmt.Errorf("Grant with ID %s dont exists", params.GrantID)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
err = oper.mdb.DeleteGrantByID(ctx, grantDescr.ID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package accoper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetAccount
|
||||||
|
type GetAccountParams struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
AccountID string `json:"accountId"`
|
||||||
|
}
|
||||||
|
type GetAccountResult struct {
|
||||||
|
Account *descr.AccountShort `json:"account"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oper *Operator) GetAccount(ctx context.Context, operatorID string, params *GetAccountParams) (*GetAccountResult, error) {
|
||||||
|
var err error
|
||||||
|
res := &GetAccountResult{}
|
||||||
|
|
||||||
|
if params.Username == "" && params.AccountID == "" {
|
||||||
|
err := fmt.Errorf("Empty username and accountId parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var accountDescr *descr.Account
|
||||||
|
var accountExists bool
|
||||||
|
switch {
|
||||||
|
case params.AccountID != "":
|
||||||
|
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !accountExists {
|
||||||
|
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
case params.Username != "":
|
||||||
|
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !accountExists {
|
||||||
|
err := fmt.Errorf("Account with name %s dont exists", params.Username)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err := fmt.Errorf("Empty username and accountId parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if accountDescr == nil {
|
||||||
|
err := fmt.Errorf("Null account desriptor")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
accountShort := &descr.AccountShort{
|
||||||
|
ID: accountDescr.ID,
|
||||||
|
Username: accountDescr.Username,
|
||||||
|
CreatedAt: accountDescr.CreatedAt,
|
||||||
|
UpdatedAt: accountDescr.UpdatedAt,
|
||||||
|
CreatedBy: accountDescr.CreatedBy,
|
||||||
|
UpdatedBy: accountDescr.UpdatedBy,
|
||||||
|
Disabled: accountDescr.Disabled,
|
||||||
|
Grants: make([]descr.Grant, 0),
|
||||||
|
}
|
||||||
|
grantDescrs, err := oper.mdb.ListGrantsByAccountID(ctx, accountDescr.ID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
accountShort.Grants = grantDescrs
|
||||||
|
|
||||||
|
res.Account = accountShort
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package accoper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get Grants
|
||||||
|
type GetGrantParams struct {
|
||||||
|
GrantID string `json:"grantId"`
|
||||||
|
}
|
||||||
|
type GetGrantResult struct {
|
||||||
|
Grant *descr.Grant `json:"grant"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oper *Operator) GetGrant(ctx context.Context, operatorID string, params *GetGrantParams) (*GetGrantResult, error) {
|
||||||
|
var err error
|
||||||
|
res := &GetGrantResult{}
|
||||||
|
|
||||||
|
if params.GrantID == "" {
|
||||||
|
err := fmt.Errorf("Empty grantId parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var grantDescr *descr.Grant
|
||||||
|
var grantExists bool
|
||||||
|
grantExists, grantDescr, err = oper.mdb.GetGrantByID(ctx, params.GrantID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !grantExists {
|
||||||
|
err := fmt.Errorf("Grant with ID %s dont exists", params.GrantID)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Grant = grantDescr
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package accoper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ListAccountsParams struct{}
|
||||||
|
type ListAccountsResult struct {
|
||||||
|
Accounts []descr.AccountShort `json:"accounts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oper *Operator) ListAccounts(ctx context.Context, params *ListAccountsParams) (*ListAccountsResult, error) {
|
||||||
|
var err error
|
||||||
|
res := &ListAccountsResult{}
|
||||||
|
|
||||||
|
accountDescrs, err := oper.mdb.ReducedListAccounts(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
for _, accountDescr := range accountDescrs {
|
||||||
|
accountShort := descr.AccountShort{
|
||||||
|
ID: accountDescr.ID,
|
||||||
|
Username: accountDescr.Username,
|
||||||
|
Disabled: accountDescr.Disabled,
|
||||||
|
CreatedAt: accountDescr.CreatedAt,
|
||||||
|
UpdatedAt: accountDescr.UpdatedAt,
|
||||||
|
CreatedBy: accountDescr.CreatedBy,
|
||||||
|
UpdatedBy: accountDescr.UpdatedBy,
|
||||||
|
Grants: make([]descr.Grant, 0),
|
||||||
|
}
|
||||||
|
grantDescrs, err := oper.mdb.ListGrantsByAccountID(ctx, accountDescr.ID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
accountShort.Grants = grantDescrs
|
||||||
|
res.Accounts = append(res.Accounts, accountShort)
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package accoper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListGrants
|
||||||
|
type ListGrantsParams struct {
|
||||||
|
Username string
|
||||||
|
AccountID string
|
||||||
|
}
|
||||||
|
type ListGrantsResult struct {
|
||||||
|
Grants []descr.Grant `json:"grants"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oper *Operator) ListGrants(ctx context.Context, operatorID string, params *ListGrantsParams) (*ListGrantsResult, error) {
|
||||||
|
var err error
|
||||||
|
res := &ListGrantsResult{
|
||||||
|
Grants: make([]descr.Grant, 0),
|
||||||
|
}
|
||||||
|
var accountDescr *descr.Account
|
||||||
|
var accountExists bool
|
||||||
|
switch {
|
||||||
|
case params.AccountID != "":
|
||||||
|
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !accountExists {
|
||||||
|
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
case params.Username != "":
|
||||||
|
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !accountExists {
|
||||||
|
err := fmt.Errorf("Account with name %s dont exists", params.Username)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err := fmt.Errorf("Empty username and accountId parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
accountID := accountDescr.ID
|
||||||
|
grantDescrs, err := oper.mdb.ListGrantsByAccountID(ctx, accountID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
res.Grants = grantDescrs
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package accoper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mbase/app/logger"
|
||||||
|
"mbase/app/maindb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OperatorParams struct {
|
||||||
|
MainDB *maindb.Database
|
||||||
|
}
|
||||||
|
|
||||||
|
type Operator struct {
|
||||||
|
mdb *maindb.Database
|
||||||
|
logg *logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOperator(params *OperatorParams) (*Operator, error) {
|
||||||
|
var err error
|
||||||
|
oper := &Operator{
|
||||||
|
mdb: params.MainDB,
|
||||||
|
}
|
||||||
|
oper.logg = logger.NewLoggerWithSubject("imageoper")
|
||||||
|
return oper, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package accoper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"mbase/pkg/auxpwd"
|
||||||
|
"mbase/pkg/auxtool"
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UpdateAccountParams struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
AccountID string `json:"accountId"`
|
||||||
|
NewUsername string `json:"newUsername"`
|
||||||
|
NewPassword string `json:"newPassword"`
|
||||||
|
Disabled bool `json:"disabled"`
|
||||||
|
}
|
||||||
|
type UpdateAccountResult struct{}
|
||||||
|
|
||||||
|
func (oper *Operator) UpdateAccount(ctx context.Context, operatorID string, params *UpdateAccountParams) (*UpdateAccountResult, error) {
|
||||||
|
var err error
|
||||||
|
res := &UpdateAccountResult{}
|
||||||
|
if params.Username == "" && params.AccountID == "" {
|
||||||
|
err := fmt.Errorf("Empty username and accountId parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
var accountDescr *descr.Account
|
||||||
|
var accountExists bool
|
||||||
|
switch {
|
||||||
|
case params.AccountID != "":
|
||||||
|
accountExists, accountDescr, err = oper.mdb.GetAccountByID(ctx, params.AccountID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !accountExists {
|
||||||
|
err := fmt.Errorf("Account with ID %s dont exists", params.AccountID)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
case params.Username != "":
|
||||||
|
accountExists, accountDescr, err = oper.mdb.GetAccountByUsername(ctx, params.Username)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !accountExists {
|
||||||
|
err := fmt.Errorf("Account with name %s dont exists", params.Username)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err := fmt.Errorf("Empty username and accountId parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if accountDescr == nil {
|
||||||
|
err := fmt.Errorf("Null account desriptor")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
now := auxtool.TimeNow()
|
||||||
|
if params.NewUsername != "" {
|
||||||
|
accountDescr.UpdatedAt = now
|
||||||
|
accountDescr.Username = params.NewUsername
|
||||||
|
}
|
||||||
|
if params.NewPassword != "" {
|
||||||
|
accountDescr.UpdatedAt = now
|
||||||
|
passhash := auxpwd.MakeSHA256Hash([]byte(params.NewPassword))
|
||||||
|
accountDescr.Passhash = passhash
|
||||||
|
}
|
||||||
|
if params.Disabled != accountDescr.Disabled {
|
||||||
|
accountDescr.UpdatedAt = now
|
||||||
|
accountDescr.Disabled = params.Disabled
|
||||||
|
}
|
||||||
|
|
||||||
|
err = oper.mdb.UpdateAccountByID(ctx, accountDescr.ID, accountDescr)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package accoper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"mbase/pkg/auxtool"
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UpdateGrant
|
||||||
|
type UpdateGrantParams struct {
|
||||||
|
GrantID string
|
||||||
|
NewPattern string
|
||||||
|
}
|
||||||
|
type UpdateGrantResult struct{}
|
||||||
|
|
||||||
|
func (oper *Operator) UpdateGrant(ctx context.Context, operatorID string, params *UpdateGrantParams) (*UpdateGrantResult, error) {
|
||||||
|
var err error
|
||||||
|
res := &UpdateGrantResult{}
|
||||||
|
|
||||||
|
if params.NewPattern == "" {
|
||||||
|
err := fmt.Errorf("Empty newPattern parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if params.GrantID == "" {
|
||||||
|
err := fmt.Errorf("Empty grantId parameter")
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
var grantDescr *descr.Grant
|
||||||
|
var grantExists bool
|
||||||
|
|
||||||
|
grantExists, grantDescr, err = oper.mdb.GetGrantByID(ctx, params.GrantID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
if !grantExists {
|
||||||
|
err := fmt.Errorf("Grant with ID %s dont exists", params.GrantID)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
now := auxtool.TimeNow()
|
||||||
|
if params.NewPattern != "" {
|
||||||
|
grantDescr.UpdatedAt = now
|
||||||
|
grantDescr.UpdatedBy = operatorID
|
||||||
|
grantDescr.Pattern = params.NewPattern
|
||||||
|
}
|
||||||
|
err = oper.mdb.UpdateGrantByID(ctx, grantDescr.ID, grantDescr)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"mbase/pkg/auxx509"
|
||||||
|
|
||||||
|
yaml "go.yaml.in/yaml/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
Address string `json:"address" yaml:"address"`
|
||||||
|
Port uint32 `json:"port" yaml:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Database struct {
|
||||||
|
Basepath string `json:"basepath" yaml:"basepath"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Storage struct {
|
||||||
|
Basepath string `json:"basepath" yaml:"basepath"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Service Service `json:"service" yaml:"service"`
|
||||||
|
Database Database `json:"database" yaml:"database"`
|
||||||
|
Storage Storage `json:"storage" yaml:"storage"`
|
||||||
|
AsDaemon bool `json:"asDaemon" yaml:"asDaemon"`
|
||||||
|
Logpath string `json:"logpath" yaml:"logpath"`
|
||||||
|
Runpath string `json:"runpath" yaml:"runpath"`
|
||||||
|
Version string `json:"version" yaml:"version"`
|
||||||
|
Certpath string `json:"certpath,omitempty" yaml:"certpath,omitempty"`
|
||||||
|
Keypath string `json:"keypath,omitempty" yaml:"keypath,omitempty"`
|
||||||
|
X509Cert string `json:"-" yaml:"-"`
|
||||||
|
X509Key string `json:"-" yaml:"-"`
|
||||||
|
Datadir string `json:"datadir" yaml:datadir`
|
||||||
|
Hostname string `json:"hostname" yaml:hostname`
|
||||||
|
Hostnames []string `json:"hostnames" yaml:hostnames`
|
||||||
|
LogLimit int64 `json:"logLimit" yaml:logLimit`
|
||||||
|
RunUser string `json:"runUser" yaml:runUser`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfig() *Config {
|
||||||
|
logfile := fmt.Sprintf("%s.log", srvname)
|
||||||
|
logpath := filepath.Join(logdir, logfile)
|
||||||
|
|
||||||
|
runfile := fmt.Sprintf("%s.pid", srvname)
|
||||||
|
runpath := filepath.Join(rundir, runfile)
|
||||||
|
|
||||||
|
//certpath := fmt.Sprintf("%s.crt", srvname)
|
||||||
|
//certpath = filepath.Join(confdir, certpath)
|
||||||
|
|
||||||
|
//keypath := fmt.Sprintf("%s.crt", srvname)
|
||||||
|
//keypath = filepath.Join(confdir, keypath)
|
||||||
|
|
||||||
|
return &Config{
|
||||||
|
Service: Service{
|
||||||
|
Address: "0.0.0.0",
|
||||||
|
Port: 1025,
|
||||||
|
},
|
||||||
|
Database: Database{
|
||||||
|
Basepath: datadir,
|
||||||
|
},
|
||||||
|
Storage: Storage{
|
||||||
|
Basepath: datadir,
|
||||||
|
},
|
||||||
|
AsDaemon: false,
|
||||||
|
Logpath: logpath,
|
||||||
|
Runpath: runpath,
|
||||||
|
Version: version,
|
||||||
|
Datadir: datadir,
|
||||||
|
//Certpath: certpath,
|
||||||
|
//Keypath: keypath,
|
||||||
|
Hostnames: make([]string, 0),
|
||||||
|
LogLimit: 1024 * 1024 * 10, // 10 Mb
|
||||||
|
RunUser: "daemon",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conf *Config) String() string {
|
||||||
|
confbytes, _ := yaml.Marshal(conf)
|
||||||
|
return string(confbytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conf *Config) ReadConfigfile() error {
|
||||||
|
conffile := fmt.Sprintf("%s.yaml", srvname)
|
||||||
|
confpath := filepath.Join(confdir, conffile)
|
||||||
|
|
||||||
|
confdata, err := ioutil.ReadFile(confpath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = yaml.Unmarshal(confdata, conf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conf *Config) ReadX509Cert() error {
|
||||||
|
var err error
|
||||||
|
if conf.Certpath != "" && conf.Keypath != "" {
|
||||||
|
if !filepath.IsAbs(conf.Certpath) {
|
||||||
|
conf.Certpath = filepath.Join(confdir, conf.Certpath)
|
||||||
|
}
|
||||||
|
certBytes, err := os.ReadFile(conf.Certpath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !filepath.IsAbs(conf.Keypath) {
|
||||||
|
conf.Keypath = filepath.Join(confdir, conf.Keypath)
|
||||||
|
}
|
||||||
|
keyBytes, err := os.ReadFile(conf.Keypath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
conf.X509Cert = string(certBytes)
|
||||||
|
conf.X509Key = string(keyBytes)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if conf.X509Cert != "" && conf.X509Key != "" {
|
||||||
|
x509Cert, err := base64.StdEncoding.DecodeString(conf.X509Cert)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
conf.X509Cert = string(x509Cert)
|
||||||
|
x509Key, err := base64.StdEncoding.DecodeString(conf.X509Key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
conf.X509Key = string(x509Key)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if conf.X509Cert == "" || conf.X509Key == "" {
|
||||||
|
if conf.Hostname == "" {
|
||||||
|
conf.Hostname, err = os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
certBytes, keyBytes, err := auxx509.CreateSelfSignedCert(conf.Hostname, conf.Hostnames...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
conf.X509Cert = string(certBytes)
|
||||||
|
conf.X509Key = string(keyBytes)
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
const (
|
||||||
|
confdir = "@srv_confdir@"
|
||||||
|
rundir = "@srv_rundir@"
|
||||||
|
logdir = "@srv_logdir@"
|
||||||
|
datadir = "@srv_datadir@"
|
||||||
|
version = "@PACKAGE_VERSION@"
|
||||||
|
srvname = "@PACKAGE_NAME@d"
|
||||||
|
)
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"mbase/app/router"
|
||||||
|
"mbase/pkg/auxhttp"
|
||||||
|
"mbase/pkg/auxpwd"
|
||||||
|
"mbase/pkg/terms"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
authTag = "authpass"
|
||||||
|
userTag = "accountID"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (hand *Handler) AuthMiddleware(next router.Handler) router.Handler {
|
||||||
|
var handlerFunc router.HandlerFunc
|
||||||
|
|
||||||
|
handlerFunc = func(rctx *router.Context) {
|
||||||
|
success, accountID, err := hand.CheckAccess(rctx)
|
||||||
|
if success {
|
||||||
|
rctx.SetBool(authTag, true)
|
||||||
|
rctx.SetString(userTag, string(accountID))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
hand.logg.Errorf("Authorization middleware error: %v", err)
|
||||||
|
}
|
||||||
|
next.ServeHTTP(rctx)
|
||||||
|
}
|
||||||
|
return handlerFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authentification
|
||||||
|
func (hand *Handler) CheckAccess(rctx *router.Context) (bool, string, error) {
|
||||||
|
var err error
|
||||||
|
var success bool
|
||||||
|
var username string
|
||||||
|
var password string
|
||||||
|
var accountID string
|
||||||
|
|
||||||
|
accountID = terms.AnonymousID
|
||||||
|
|
||||||
|
//hand.logg.Debugf("URL: %s", rctx.URL().String())
|
||||||
|
authHeader := rctx.GetHeader("Authorization")
|
||||||
|
hand.logg.Debugf("Authorization: [%s]", authHeader)
|
||||||
|
if authHeader != "" {
|
||||||
|
username, password, err = auxhttp.ParseBasicAuth(authHeader)
|
||||||
|
if err != nil {
|
||||||
|
return success, accountID, err
|
||||||
|
}
|
||||||
|
if username == "" || password == "" {
|
||||||
|
goto anonymous
|
||||||
|
}
|
||||||
|
|
||||||
|
success, id, err := hand.ValidatePassword(rctx.Ctx, username, password)
|
||||||
|
if err != nil {
|
||||||
|
return false, accountID, err
|
||||||
|
}
|
||||||
|
if !success {
|
||||||
|
err = fmt.Errorf("Incorrect username or password")
|
||||||
|
return false, accountID, err
|
||||||
|
}
|
||||||
|
accountID = id
|
||||||
|
return success, accountID, err
|
||||||
|
}
|
||||||
|
anonymous:
|
||||||
|
success = true
|
||||||
|
accountID = terms.AnonymousID
|
||||||
|
return success, accountID, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand *Handler) ValidatePassword(ctx context.Context, username, password string) (bool, string, error) {
|
||||||
|
var err error
|
||||||
|
var accountID string
|
||||||
|
valid := false
|
||||||
|
|
||||||
|
accountExists, accountDescr, err := hand.mdb.GetAccountByUsername(ctx, username)
|
||||||
|
if !accountExists {
|
||||||
|
err := fmt.Errorf("Account not exists")
|
||||||
|
return valid, accountID, err
|
||||||
|
}
|
||||||
|
if !auxpwd.PasswordMatch([]byte(password), accountDescr.Passhash) {
|
||||||
|
err := fmt.Errorf("Login data mismatch")
|
||||||
|
return valid, accountID, err
|
||||||
|
}
|
||||||
|
valid = true
|
||||||
|
accountID = accountDescr.ID
|
||||||
|
|
||||||
|
return valid, accountID, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authorization
|
||||||
|
func (hand *Handler) CheckRight(ctx context.Context, accountID, reqRight, subject string) (bool, error) {
|
||||||
|
var err error
|
||||||
|
var res bool
|
||||||
|
res = true
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"mbase/app/accoper"
|
||||||
|
"mbase/app/router"
|
||||||
|
"mbase/pkg/terms"
|
||||||
|
)
|
||||||
|
|
||||||
|
// POST /v3/account/create 200 200
|
||||||
|
func (hand *Handler) CreateAccount(rctx *router.Context) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
params := &accoper.CreateAccountParams{}
|
||||||
|
err = rctx.BindJSON(params)
|
||||||
|
if err != nil {
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Rigth checking
|
||||||
|
operatorID, _ := rctx.GetString(userTag)
|
||||||
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteAccounts, "")
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Operation error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !opEnable {
|
||||||
|
err := fmt.Errorf("Operation not enabled for this account")
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Execution of the operation
|
||||||
|
res, err := hand.acop.CreateAccount(rctx.Ctx, operatorID, params)
|
||||||
|
if err != nil {
|
||||||
|
hand.logg.Errorf("Operation error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hand.SendResult(rctx, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /v3/account/get 200 200
|
||||||
|
func (hand *Handler) GetAccount(rctx *router.Context) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
params := &accoper.GetAccountParams{}
|
||||||
|
err = rctx.BindJSON(params)
|
||||||
|
if err != nil {
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Rigth checking
|
||||||
|
operatorID, _ := rctx.GetString(userTag)
|
||||||
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteAccounts, "")
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Operation error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !opEnable {
|
||||||
|
err := fmt.Errorf("Operation not enabled for this account")
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Execution of the operation
|
||||||
|
res, err := hand.acop.GetAccount(rctx.Ctx, operatorID, params)
|
||||||
|
if err != nil {
|
||||||
|
hand.logg.Errorf("Operation error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hand.SendResult(rctx, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /v3/accounts/list 200 200
|
||||||
|
func (hand *Handler) ListAccounts(rctx *router.Context) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
params := &accoper.ListAccountsParams{}
|
||||||
|
err = rctx.BindJSON(params)
|
||||||
|
if err != nil {
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Rigth checking
|
||||||
|
operatorID, _ := rctx.GetString(userTag)
|
||||||
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteAccounts, "")
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Operation error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !opEnable {
|
||||||
|
err := fmt.Errorf("Operation not enabled for this account")
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Execution of the operation
|
||||||
|
res, err := hand.acop.ListAccounts(rctx.Ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
hand.logg.Errorf("ListAccounts error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hand.SendResult(rctx, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /v3/account/get 200 200
|
||||||
|
func (hand *Handler) UpdateAccount(rctx *router.Context) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
params := &accoper.UpdateAccountParams{}
|
||||||
|
err = rctx.BindJSON(params)
|
||||||
|
if err != nil {
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Rigth checking
|
||||||
|
operatorID, _ := rctx.GetString(userTag)
|
||||||
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteAccounts, "")
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Operation error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !opEnable {
|
||||||
|
err := fmt.Errorf("Operation not enabled for this account")
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Execution of the operation
|
||||||
|
res, err := hand.acop.UpdateAccount(rctx.Ctx, operatorID, params)
|
||||||
|
if err != nil {
|
||||||
|
hand.logg.Errorf("UpdateAccount error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hand.SendResult(rctx, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /v3/account/delete 200 200
|
||||||
|
func (hand *Handler) DeleteAccount(rctx *router.Context) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
params := &accoper.DeleteAccountParams{}
|
||||||
|
err = rctx.BindJSON(params)
|
||||||
|
if err != nil {
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Rigth checking
|
||||||
|
operatorID, _ := rctx.GetString(userTag)
|
||||||
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteAccounts, params.Username)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Operation error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !opEnable {
|
||||||
|
err := fmt.Errorf("Operation not enabled for this account")
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Execution of the operation
|
||||||
|
res, err := hand.acop.DeleteAccount(rctx.Ctx, operatorID, params)
|
||||||
|
if err != nil {
|
||||||
|
hand.logg.Errorf("DeleteAccount error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hand.SendResult(rctx, res)
|
||||||
|
}
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"mbase/app/accoper"
|
||||||
|
"mbase/app/router"
|
||||||
|
"mbase/pkg/terms"
|
||||||
|
)
|
||||||
|
|
||||||
|
// POST /v3/grant/create 200 200
|
||||||
|
func (hand *Handler) CreateGrant(rctx *router.Context) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
params := &accoper.CreateGrantParams{}
|
||||||
|
err = rctx.BindJSON(params)
|
||||||
|
if err != nil {
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Rigth checking
|
||||||
|
operatorID, _ := rctx.GetString(userTag)
|
||||||
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteAccounts, "")
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Operation error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !opEnable {
|
||||||
|
err := fmt.Errorf("Operation not enabled for this account")
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Execution of the operation
|
||||||
|
res, err := hand.acop.CreateGrant(rctx.Ctx, operatorID, params)
|
||||||
|
if err != nil {
|
||||||
|
hand.logg.Errorf("CreateGrant error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hand.SendResult(rctx, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /v3/grant/get 200 200
|
||||||
|
func (hand *Handler) GetGrant(rctx *router.Context) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
params := &accoper.GetGrantParams{}
|
||||||
|
err = rctx.BindJSON(params)
|
||||||
|
if err != nil {
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Rigth checking
|
||||||
|
operatorID, _ := rctx.GetString(userTag)
|
||||||
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadAccounts, "")
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Operation error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !opEnable {
|
||||||
|
err := fmt.Errorf("Operation not enabled for this account")
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Execution of the operation
|
||||||
|
res, err := hand.acop.GetGrant(rctx.Ctx, operatorID, params)
|
||||||
|
if err != nil {
|
||||||
|
hand.logg.Errorf("CreateGrant error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hand.SendResult(rctx, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /v3/grants/list 200 200
|
||||||
|
func (hand *Handler) ListGrants(rctx *router.Context) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
params := &accoper.ListGrantsParams{}
|
||||||
|
err = rctx.BindJSON(params)
|
||||||
|
if err != nil {
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Rigth checking
|
||||||
|
operatorID, _ := rctx.GetString(userTag)
|
||||||
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightReadAccounts, "")
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Operation error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !opEnable {
|
||||||
|
err := fmt.Errorf("Operation not enabled for this account")
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Execution of the operation
|
||||||
|
res, err := hand.acop.ListGrants(rctx.Ctx, operatorID, params)
|
||||||
|
if err != nil {
|
||||||
|
hand.logg.Errorf("ListGrants error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hand.SendResult(rctx, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /v3/grant/get 200 200
|
||||||
|
func (hand *Handler) UpdateGrant(rctx *router.Context) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
params := &accoper.UpdateGrantParams{}
|
||||||
|
err = rctx.BindJSON(params)
|
||||||
|
if err != nil {
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Rigth checking
|
||||||
|
operatorID, _ := rctx.GetString(userTag)
|
||||||
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteAccounts, "")
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Operation error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !opEnable {
|
||||||
|
err := fmt.Errorf("Operation not enabled for this account")
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Execution of the operation
|
||||||
|
res, err := hand.acop.UpdateGrant(rctx.Ctx, operatorID, params)
|
||||||
|
if err != nil {
|
||||||
|
hand.logg.Errorf("UpdateGrant error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hand.SendResult(rctx, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /v3/grant/delete 200 200
|
||||||
|
func (hand *Handler) DeleteGrant(rctx *router.Context) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
params := &accoper.DeleteGrantParams{}
|
||||||
|
err = rctx.BindJSON(params)
|
||||||
|
if err != nil {
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Rigth checking
|
||||||
|
operatorID, _ := rctx.GetString(userTag)
|
||||||
|
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, terms.RightWriteAccounts, "")
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Operation error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !opEnable {
|
||||||
|
err := fmt.Errorf("Operation not enabled for this account")
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Execution of the operation
|
||||||
|
res, err := hand.acop.DeleteGrant(rctx.Ctx, operatorID, params)
|
||||||
|
if err != nil {
|
||||||
|
hand.logg.Errorf("DeleteGrant error: %v", err)
|
||||||
|
hand.SendError(rctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hand.SendResult(rctx, res)
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mbase/app/logger"
|
||||||
|
"mbase/app/maindb"
|
||||||
|
"mbase/app/router"
|
||||||
|
|
||||||
|
"mbase/app/accoper"
|
||||||
|
"mbase/app/servoper"
|
||||||
|
|
||||||
|
yaml "go.yaml.in/yaml/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HandlerParams struct {
|
||||||
|
MainDB *maindb.Database
|
||||||
|
AccOper *accoper.Operator
|
||||||
|
ServOper *servoper.Operator
|
||||||
|
}
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
mdb *maindb.Database
|
||||||
|
logg *logger.Logger
|
||||||
|
acop *accoper.Operator
|
||||||
|
seop *servoper.Operator
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandler(params *HandlerParams) (*Handler, error) {
|
||||||
|
var err error
|
||||||
|
hand := &Handler{
|
||||||
|
mdb: params.MainDB,
|
||||||
|
acop: params.AccOper,
|
||||||
|
seop: params.ServOper,
|
||||||
|
}
|
||||||
|
hand.logg = logger.NewLoggerWithSubject("handler")
|
||||||
|
return hand, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand *Handler) DumpHeaders(label string, rctx *router.Context) {
|
||||||
|
headers := rctx.GetHeaders()
|
||||||
|
yamlData, _ := yaml.Marshal(headers)
|
||||||
|
hand.logg.Debugf("%s:\n%s\n", label, string(yamlData))
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"mbase/app/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (hand *Handler) NotFound(rctx *router.Context) {
|
||||||
|
hand.logg.Warningf("Route for [%s %s] not found", rctx.Request.Method, rctx.Request.URL.String())
|
||||||
|
rctx.SetStatus(http.StatusNotFound)
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"mbase/app/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Response[T any] struct {
|
||||||
|
Error bool `json:"error" yaml:"error"`
|
||||||
|
Message string `json:"message,omitempty" yaml:"message,omitempty"`
|
||||||
|
Result T `json:"result,omitempty" yaml:"result,result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResponse[T any]() *Response[T] {
|
||||||
|
return &Response[T]{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand *Handler) SendResult(rctx *router.Context, result any) {
|
||||||
|
response := &Response[any]{
|
||||||
|
Error: false,
|
||||||
|
Result: result,
|
||||||
|
}
|
||||||
|
rctx.SendJSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand *Handler) SendError(rctx *router.Context, err error) {
|
||||||
|
response := &Response[any]{
|
||||||
|
Error: true,
|
||||||
|
Message: err.Error(),
|
||||||
|
}
|
||||||
|
rctx.SendJSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mbase/app/servoper"
|
||||||
|
"mbase/app/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (hand *Handler) SendHello(rctx *router.Context) {
|
||||||
|
params := &servoper.SendHelloParams{}
|
||||||
|
res, _ := hand.seop.SendHello(params)
|
||||||
|
hand.SendResult(rctx, res)
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package locker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Elem struct {
|
||||||
|
Pipe chan bool
|
||||||
|
Usage int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewElem() *Elem {
|
||||||
|
return &Elem{
|
||||||
|
Pipe: make(chan bool, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Locker struct {
|
||||||
|
mtx sync.Mutex
|
||||||
|
lMap map[string]*Elem
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLocker() *Locker {
|
||||||
|
lock := &Locker{
|
||||||
|
lMap: make(map[string]*Elem),
|
||||||
|
}
|
||||||
|
return lock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lock *Locker) WaitAndLock(name string) {
|
||||||
|
lock.mtx.Lock()
|
||||||
|
p, exist := lock.lMap[name]
|
||||||
|
if !exist {
|
||||||
|
p = NewElem()
|
||||||
|
lock.lMap[name] = p
|
||||||
|
p.Pipe <- true
|
||||||
|
}
|
||||||
|
p.Usage += 1
|
||||||
|
lock.mtx.Unlock()
|
||||||
|
select {
|
||||||
|
case <-p.Pipe:
|
||||||
|
// NOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lock *Locker) Done(name string) {
|
||||||
|
lock.mtx.Lock()
|
||||||
|
p, exist := lock.lMap[name]
|
||||||
|
if exist {
|
||||||
|
p.Pipe <- true
|
||||||
|
if p.Usage > 0 {
|
||||||
|
p.Usage -= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
garbageKeys := make([]string, 0)
|
||||||
|
for key, _ := range lock.lMap {
|
||||||
|
elem := lock.lMap[key]
|
||||||
|
if elem.Usage == 0 && key != name {
|
||||||
|
garbageKeys = append(garbageKeys, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, key := range garbageKeys {
|
||||||
|
delete(lock.lMap, key)
|
||||||
|
}
|
||||||
|
lock.mtx.Unlock()
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package locker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Runner struct {
|
||||||
|
lock *Locker
|
||||||
|
res sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRunner() *Runner {
|
||||||
|
return &Runner{
|
||||||
|
lock: NewLocker(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Runner) Run(wg *sync.WaitGroup, resName string, t *testing.T) {
|
||||||
|
for n := 2; n < 1000; n++ {
|
||||||
|
r.lock.WaitAndLock(resName)
|
||||||
|
|
||||||
|
val := fmt.Sprintf("%d", n)
|
||||||
|
r.res.Store(resName, val)
|
||||||
|
|
||||||
|
td := time.Duration(rand.Uint64()%1000 + 1)
|
||||||
|
time.Sleep(td * time.Nanosecond)
|
||||||
|
|
||||||
|
foo, exist := r.res.Load(resName)
|
||||||
|
if !exist {
|
||||||
|
t.Errorf("not exist!\n")
|
||||||
|
}
|
||||||
|
if foo != val {
|
||||||
|
t.Errorf("not val!\n")
|
||||||
|
}
|
||||||
|
r.res.Delete(resName)
|
||||||
|
r.lock.Done(resName)
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLocker(t *testing.T) {
|
||||||
|
run := NewRunner()
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for n := 1; n < 200; n++ {
|
||||||
|
go run.Run(&wg, "foo", t)
|
||||||
|
wg.Add(1)
|
||||||
|
}
|
||||||
|
for n := 1; n < 200; n++ {
|
||||||
|
go run.Run(&wg, "foo/bare", t)
|
||||||
|
wg.Add(1)
|
||||||
|
}
|
||||||
|
for n := 1; n < 200; n++ {
|
||||||
|
go run.Run(&wg, "foo/bare/foo", t)
|
||||||
|
wg.Add(1)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mtx sync.Mutex
|
||||||
|
output io.WriteCloser = os.Stderr
|
||||||
|
)
|
||||||
|
|
||||||
|
type Logger struct {
|
||||||
|
subject string
|
||||||
|
writer io.WriteCloser
|
||||||
|
mtx *sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLoggerWithSubject(subj string) *Logger {
|
||||||
|
return &Logger{
|
||||||
|
subject: subj,
|
||||||
|
writer: output,
|
||||||
|
mtx: &mtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLogger() *Logger {
|
||||||
|
return &Logger{
|
||||||
|
writer: output,
|
||||||
|
mtx: &mtx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetWriter(newOut io.WriteCloser) {
|
||||||
|
mtx.Lock()
|
||||||
|
output = newOut
|
||||||
|
mtx.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logg *Logger) SetWriter(newOut io.WriteCloser) {
|
||||||
|
mtx.Lock()
|
||||||
|
logg.writer = newOut
|
||||||
|
var newMtx sync.Mutex
|
||||||
|
logg.mtx = &newMtx
|
||||||
|
mtx.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logg *Logger) Debugf(message string, args ...any) {
|
||||||
|
logg.printf("debug", message, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logg *Logger) Infof(message string, args ...any) {
|
||||||
|
logg.printf("info", message, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logg *Logger) Warningf(message string, args ...any) {
|
||||||
|
logg.printf("warning", message, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logg *Logger) Errorf(message string, args ...any) {
|
||||||
|
logg.printf("error", message, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logg *Logger) printf(level, message string, args ...any) {
|
||||||
|
timestamp := time.Now().Format(time.RFC3339)
|
||||||
|
buffer := bytes.NewBuffer([]byte{})
|
||||||
|
if logg.subject != "" {
|
||||||
|
fmt.Fprintf(buffer, "%s %s.%s: ", timestamp, logg.subject, level)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(buffer, "%s %s: ", timestamp, level)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(buffer, message, args...)
|
||||||
|
fmt.Fprintf(buffer, "\n")
|
||||||
|
logg.mtx.Lock()
|
||||||
|
fmt.Fprint(output, buffer.String())
|
||||||
|
logg.mtx.Unlock()
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLogger(t *testing.T) {
|
||||||
|
logg := NewLogger("test")
|
||||||
|
logg.Debugf("foo: %s", "bar")
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLoggerL(b *testing.B) {
|
||||||
|
SetWriter(ioutil.Discard)
|
||||||
|
logg := NewLogger("test")
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
logg.Debugf("foo: %s", "bar")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLoggerP(b *testing.B) {
|
||||||
|
SetWriter(ioutil.Discard)
|
||||||
|
logg := NewLogger("test")
|
||||||
|
b.ResetTimer()
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
logg.Debugf("foo: %s", "bar")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package maindb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (db *Database) InsertAccount(ctx context.Context, account *descr.Account) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
request := `INSERT INTO accounts(id, username, passhash, disabled, created_at, updated_at, created_by, updated_by)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`
|
||||||
|
_, err = db.db.Exec(request, account.ID, account.Username, account.Passhash, account.Disabled,
|
||||||
|
account.CreatedAt, account.UpdatedAt, account.CreatedBy, account.UpdatedBy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) UpdateAccountByID(ctx context.Context, accountID string, account *descr.Account) error {
|
||||||
|
var err error
|
||||||
|
request := `UPDATE accounts SET username = $1, passhash = $2, disabled = $3, updated_at = $4, updated_by = $5 WHERE id = $6`
|
||||||
|
_, err = db.db.Exec(request, account.Username, account.Passhash, account.Disabled, account.UpdatedAt, account.UpdatedBy, accountID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) ReducedListAccounts(ctx context.Context) ([]descr.Account, error) {
|
||||||
|
var err error
|
||||||
|
request := `SELECT id, username, disabled, created_at, updated_at, created_by, updated_by FROM accounts`
|
||||||
|
res := make([]descr.Account, 0)
|
||||||
|
err = db.db.Select(&res, request)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) ListAccounts(ctx context.Context) ([]descr.Account, error) {
|
||||||
|
var err error
|
||||||
|
request := `SELECT * FROM accounts`
|
||||||
|
res := make([]descr.Account, 0)
|
||||||
|
err = db.db.Select(&res, request)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) GetAccountByID(ctx context.Context, accountID string) (bool, *descr.Account, error) {
|
||||||
|
var err error
|
||||||
|
var res *descr.Account
|
||||||
|
var exists bool = false
|
||||||
|
|
||||||
|
request := `SELECT * FROM accounts WHERE id = $1 LiMIT 1`
|
||||||
|
dbRes := make([]descr.Account, 0)
|
||||||
|
err = db.db.Select(&dbRes, request, accountID)
|
||||||
|
if err != nil {
|
||||||
|
return exists, res, err
|
||||||
|
}
|
||||||
|
if len(dbRes) == 0 {
|
||||||
|
return exists, res, err
|
||||||
|
}
|
||||||
|
exists = true
|
||||||
|
res = &dbRes[0]
|
||||||
|
return exists, res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) GetAccountByUsername(ctx context.Context, username string) (bool, *descr.Account, error) {
|
||||||
|
var err error
|
||||||
|
var res *descr.Account
|
||||||
|
var exists bool
|
||||||
|
|
||||||
|
request := `SELECT * FROM accounts WHERE username = $1 LIMIT 1`
|
||||||
|
dbRes := make([]descr.Account, 0)
|
||||||
|
err = db.db.Select(&dbRes, request, username)
|
||||||
|
if err != nil {
|
||||||
|
return exists, res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dbRes) == 0 {
|
||||||
|
return false, res, err
|
||||||
|
}
|
||||||
|
exists = true
|
||||||
|
res = &dbRes[0]
|
||||||
|
return exists, res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) DeleteAccountByID(ctx context.Context, accountID string) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
request := `DELETE FROM accounts WHERE id = $1`
|
||||||
|
_, err = db.db.Exec(request, accountID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) DeleteAccountByUsername(ctx context.Context, username string) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
request := `DELETE FROM accounts WHERE username = $1`
|
||||||
|
_, err = db.db.Exec(request, username)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package maindb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (db *Database) InsertGrant(ctx context.Context, grant *descr.Grant) error {
|
||||||
|
var err error
|
||||||
|
request := `INSERT INTO grants(id, account_id, right, pattern, created_at, updated_at, created_by, updated_by)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`
|
||||||
|
_, err = db.db.Exec(request, grant.ID, grant.AccountID, grant.Right, grant.Pattern,
|
||||||
|
grant.CreatedAt, grant.UpdatedAt, grant.CreatedBy, grant.UpdatedBy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) UpdateGrantByID(ctx context.Context, grantID string, grant *descr.Grant) error {
|
||||||
|
var err error
|
||||||
|
request := `UPDATE grants SET pattern = $1, updated_at = $2, updated_by = $3 WHERE id = $4`
|
||||||
|
_, err = db.db.Exec(request, grant.Pattern, grant.UpdatedAt, grant.UpdatedBy, grantID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) ListGrantsByAccountID(ctx context.Context, accountID string) ([]descr.Grant, error) {
|
||||||
|
var err error
|
||||||
|
request := `SELECT * FROM grants WHERE account_id = $1`
|
||||||
|
res := make([]descr.Grant, 0)
|
||||||
|
err = db.db.Select(&res, request, accountID)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) ListGrants(ctx context.Context) ([]descr.Grant, error) {
|
||||||
|
var err error
|
||||||
|
request := `SELECT * FROM grants`
|
||||||
|
res := make([]descr.Grant, 0)
|
||||||
|
err = db.db.Select(&res, request)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) GetGrantByID(ctx context.Context, garntID string) (bool, *descr.Grant, error) {
|
||||||
|
var err error
|
||||||
|
res := &descr.Grant{}
|
||||||
|
request := `SELECT * FROM grants WHERE id = $1 LIMIT 1`
|
||||||
|
dbRes := make([]descr.Grant, 0)
|
||||||
|
err = db.db.Select(&dbRes, request, garntID)
|
||||||
|
if err != nil {
|
||||||
|
return false, res, err
|
||||||
|
}
|
||||||
|
if len(dbRes) == 0 {
|
||||||
|
return false, res, err
|
||||||
|
|
||||||
|
}
|
||||||
|
res = &dbRes[0]
|
||||||
|
return true, res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) GetGrantByAccoundIDRight(ctx context.Context, accountID, right string) (bool, *descr.Grant, error) {
|
||||||
|
var err error
|
||||||
|
res := &descr.Grant{}
|
||||||
|
request := `SELECT * FROM grants WHERE account_id = $1 AND right = $2 LIMIT 1`
|
||||||
|
dbRes := make([]descr.Grant, 0)
|
||||||
|
err = db.db.Select(&dbRes, request, accountID, right)
|
||||||
|
if err != nil {
|
||||||
|
return false, res, err
|
||||||
|
}
|
||||||
|
if len(dbRes) == 0 {
|
||||||
|
return false, res, err
|
||||||
|
|
||||||
|
}
|
||||||
|
res = &dbRes[0]
|
||||||
|
return true, res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) ListGrantsByAccoundIDRight(ctx context.Context, accountID, right string) (bool, []descr.Grant, error) {
|
||||||
|
var err error
|
||||||
|
request := `SELECT * FROM grants WHERE account_id = $1 AND right = $2`
|
||||||
|
res := make([]descr.Grant, 0)
|
||||||
|
err = db.db.Select(&res, request, accountID, right)
|
||||||
|
if err != nil {
|
||||||
|
return false, res, err
|
||||||
|
}
|
||||||
|
if len(res) == 0 {
|
||||||
|
return false, res, err
|
||||||
|
}
|
||||||
|
return true, res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) GetGrantByAccoundIDRightPattern(ctx context.Context, accountID, right, pattern string) (bool, *descr.Grant, error) {
|
||||||
|
var err error
|
||||||
|
res := &descr.Grant{}
|
||||||
|
request := `SELECT * FROM grants WHERE account_id = $1 AND right = $2 AND pattern = $3 LIMIT 1`
|
||||||
|
dbRes := make([]descr.Grant, 0)
|
||||||
|
err = db.db.Select(&dbRes, request, accountID, right, pattern)
|
||||||
|
if err != nil {
|
||||||
|
return false, res, err
|
||||||
|
}
|
||||||
|
if len(dbRes) == 0 {
|
||||||
|
return false, res, err
|
||||||
|
|
||||||
|
}
|
||||||
|
res = &dbRes[0]
|
||||||
|
return true, res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) DeleteGrantByAccountIDRightPattern(ctx context.Context, accountID, right, pattern string) error {
|
||||||
|
var err error
|
||||||
|
request := `DELETE FROM grants WHERE account_id = $1 AND right = $2 AND pattern = $3`
|
||||||
|
_, err = db.db.Exec(request, accountID, right, pattern)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) DeleteGrantByID(ctx context.Context, grantID string) error {
|
||||||
|
var err error
|
||||||
|
request := `DELETE FROM grants WHERE id = $1`
|
||||||
|
_, err = db.db.Exec(request, grantID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) DeleteAllGrantsForAccountID(ctx context.Context, grantID string) error {
|
||||||
|
var err error
|
||||||
|
request := `DELETE FROM grants WHERE account_id = $1`
|
||||||
|
_, err = db.db.Exec(request, grantID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package maindb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"mbase/pkg/auxtool"
|
||||||
|
"mbase/pkg/auxuuid"
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGrant(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
dbDir := t.TempDir()
|
||||||
|
db := NewDatabase(dbDir)
|
||||||
|
|
||||||
|
err = db.OpenDatabase()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = db.InitDatabase()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
id := auxuuid.NewUUID()
|
||||||
|
accountID := auxuuid.NewUUID()
|
||||||
|
timenow := auxtool.TimeNow()
|
||||||
|
creator := auxuuid.NewUUID()
|
||||||
|
newGrant := &descr.Grant{
|
||||||
|
ID: id,
|
||||||
|
AccountID: accountID,
|
||||||
|
Right: "rigthFoo",
|
||||||
|
Pattern: `*`,
|
||||||
|
CreatedAt: timenow,
|
||||||
|
UpdatedAt: timenow,
|
||||||
|
CreatedBy: creator,
|
||||||
|
UpdatedBy: creator,
|
||||||
|
}
|
||||||
|
ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
|
||||||
|
|
||||||
|
err = db.InsertGrant(ctx, newGrant)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
files, err := db.ListGrantsByAccountID(ctx, accountID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(files), 1)
|
||||||
|
require.Equal(t, files[0].ID, id)
|
||||||
|
require.Equal(t, files[0].AccountID, accountID)
|
||||||
|
require.Equal(t, files[0].CreatedBy, creator)
|
||||||
|
fmt.Println(files[0].CreatedBy)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package maindb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"mbase/pkg/auxpwd"
|
||||||
|
"mbase/pkg/auxtool"
|
||||||
|
"mbase/pkg/auxuuid"
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
"mbase/pkg/terms"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (db *Database) WriteAnonymous(ctx context.Context) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
now := auxtool.TimeNow()
|
||||||
|
password := auxtool.RandomString(64)
|
||||||
|
passhash := auxpwd.MakeSHA256Hash([]byte(password))
|
||||||
|
accountDescr := &descr.Account{
|
||||||
|
ID: terms.AnonymousID,
|
||||||
|
Username: terms.AnonimousUsername,
|
||||||
|
Passhash: passhash,
|
||||||
|
Disabled: false,
|
||||||
|
CreatedAt: now,
|
||||||
|
UpdatedAt: now,
|
||||||
|
CreatedBy: terms.ServerID,
|
||||||
|
UpdatedBy: terms.ServerID,
|
||||||
|
}
|
||||||
|
err = db.InsertAccount(ctx, accountDescr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) WriteInituser(ctx context.Context) error {
|
||||||
|
var err error
|
||||||
|
now := auxtool.TimeNow()
|
||||||
|
passhash := auxpwd.MakeSHA256Hash([]byte(terms.InitUsername))
|
||||||
|
accountDescr := &descr.Account{
|
||||||
|
ID: terms.InitID,
|
||||||
|
Username: terms.InitUsername,
|
||||||
|
Passhash: passhash,
|
||||||
|
Disabled: false,
|
||||||
|
CreatedAt: now,
|
||||||
|
UpdatedAt: now,
|
||||||
|
CreatedBy: terms.ServerID,
|
||||||
|
UpdatedBy: terms.ServerID,
|
||||||
|
}
|
||||||
|
err = db.InsertAccount(ctx, accountDescr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fullRights := []string{
|
||||||
|
terms.RightWriteAccounts,
|
||||||
|
terms.RightReadAccounts,
|
||||||
|
}
|
||||||
|
for _, right := range fullRights {
|
||||||
|
grantDescr := &descr.Grant{
|
||||||
|
ID: auxuuid.NewUUID(),
|
||||||
|
AccountID: accountDescr.ID,
|
||||||
|
Right: right,
|
||||||
|
Pattern: ".*",
|
||||||
|
CreatedAt: now,
|
||||||
|
UpdatedAt: now,
|
||||||
|
CreatedBy: terms.ServerID,
|
||||||
|
UpdatedBy: terms.ServerID,
|
||||||
|
}
|
||||||
|
err = db.InsertGrant(ctx, grantDescr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package maindb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"mbase/app/logger"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Database struct {
|
||||||
|
datapath string
|
||||||
|
logg *logger.Logger
|
||||||
|
db *sqlx.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDatabase(datapath string) *Database {
|
||||||
|
return &Database{
|
||||||
|
datapath: datapath,
|
||||||
|
logg: logger.NewLoggerWithSubject("maindb"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) OpenDatabase() error {
|
||||||
|
var err error
|
||||||
|
dbPath := filepath.Join(db.datapath, "mbase.db")
|
||||||
|
db.db, err = sqlx.Open("sqlite3", fmt.Sprintf("%s?cache=shared&mode=rwc&_journal_mode=WAL", dbPath))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Open database error: %v", err)
|
||||||
|
}
|
||||||
|
err = db.db.Ping()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Ping database error: %v", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *Database) InitDatabase() error {
|
||||||
|
var err error
|
||||||
|
_, err = db.db.Exec(schema)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Init database error: %v", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package maindb
|
||||||
|
|
||||||
|
const schema = `
|
||||||
|
--- DROP TABLE IF EXISTS accounts;
|
||||||
|
CREATE TABLE IF NOT EXISTS accounts (
|
||||||
|
id TEXT NOT NULL,
|
||||||
|
username TEXT NOT NULL,
|
||||||
|
passhash TEXT NOT NULL,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL,
|
||||||
|
created_by TEXT NOT NULL,
|
||||||
|
updated_by TEXT NOT NULL,
|
||||||
|
disabled BOOL
|
||||||
|
);
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS accounts_index01
|
||||||
|
ON accounts(id);
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS accounts_index02
|
||||||
|
ON accounts(username);
|
||||||
|
|
||||||
|
--- DROP TABLE IF EXISTS grants;
|
||||||
|
CREATE TABLE IF NOT EXISTS grants (
|
||||||
|
id TEXT NOT NULL,
|
||||||
|
account_id INT NOT NULL,
|
||||||
|
right TEXT NOT NULL,
|
||||||
|
pattern TEXT NOT NULL,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL,
|
||||||
|
created_by TEXT NOT NULL,
|
||||||
|
updated_by TEXT NOT NULL
|
||||||
|
);
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS grants_index00
|
||||||
|
ON grants(id);
|
||||||
|
CREATE INDEX IF NOT EXISTS grants_index01
|
||||||
|
ON grants(account_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS grants_index02
|
||||||
|
ON grants(account_id, right);
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS grants_index03
|
||||||
|
ON grants(account_id, right, pattern);
|
||||||
|
|
||||||
|
`
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The code reflect string-string map to taged structure
|
||||||
|
// Limited, used only base types
|
||||||
|
// Don't ask me how it works. I'm only writer ;)
|
||||||
|
|
||||||
|
func bindObj(obj interface{}, kvmap map[string]string, sTag string) error {
|
||||||
|
var err error
|
||||||
|
vElem := reflect.ValueOf(obj).Elem()
|
||||||
|
sElem := reflect.TypeOf(obj).Elem()
|
||||||
|
for i := 0; i < vElem.NumField(); i++ {
|
||||||
|
vField := vElem.Field(i)
|
||||||
|
tag := sElem.Field(i).Tag.Get(sTag)
|
||||||
|
if tag != "" {
|
||||||
|
sVal, exists := kvmap[tag]
|
||||||
|
if exists {
|
||||||
|
switch vField.Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
vField.SetString(sVal)
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
iVal, err := strconv.ParseInt(sVal, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
vField.SetInt(iVal)
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
iVal, err := strconv.ParseUint(sVal, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
vField.SetUint(iVal)
|
||||||
|
case reflect.Bool:
|
||||||
|
bVal, err := strconv.ParseBool(sVal)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
vField.SetBool(bVal)
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
fVal, err := strconv.ParseFloat(sVal, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
vField.SetFloat(fVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Context struct {
|
||||||
|
Ctx context.Context
|
||||||
|
Request *http.Request
|
||||||
|
Writer http.ResponseWriter
|
||||||
|
PathMap map[string]string
|
||||||
|
Bools map[string]bool
|
||||||
|
Strings map[string]string
|
||||||
|
StatusCode int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewContext(writer http.ResponseWriter, request *http.Request) *Context {
|
||||||
|
rctx := &Context{
|
||||||
|
Writer: writer,
|
||||||
|
Request: request,
|
||||||
|
Ctx: request.Context(),
|
||||||
|
PathMap: make(map[string]string),
|
||||||
|
Bools: make(map[string]bool),
|
||||||
|
Strings: make(map[string]string),
|
||||||
|
}
|
||||||
|
return rctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aux maps
|
||||||
|
func (rctx *Context) SetBool(key string, value bool) {
|
||||||
|
rctx.Bools[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) GetBool(key string) (bool, bool) {
|
||||||
|
exists, value := rctx.Bools[key]
|
||||||
|
return exists, value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) SetString(key string, value string) {
|
||||||
|
rctx.Strings[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) GetString(key string) (string, bool) {
|
||||||
|
value, exists := rctx.Strings[key]
|
||||||
|
return value, exists
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request
|
||||||
|
func (rctx *Context) GetSubpath(key string) (string, bool) {
|
||||||
|
value, exists := rctx.PathMap[key]
|
||||||
|
return value, exists
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) URL() *url.URL {
|
||||||
|
return rctx.Request.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) GetQuery(key string) string {
|
||||||
|
return rctx.Request.URL.Query().Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) GetHeader(key string) string {
|
||||||
|
return rctx.Request.Header.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) GetHeaders() http.Header {
|
||||||
|
return rctx.Request.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) GetContext() context.Context {
|
||||||
|
return rctx.Request.Context()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binding
|
||||||
|
const emptyJSON = "{}"
|
||||||
|
|
||||||
|
func (rctx *Context) BindJSON(obj any) error {
|
||||||
|
buffer := bytes.NewBuffer(nil)
|
||||||
|
_, err := io.Copy(buffer, rctx.Request.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
reqBody := buffer.Bytes()
|
||||||
|
if len(reqBody) == 0 {
|
||||||
|
reqBody = []byte(emptyJSON)
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(reqBody, obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) BindQuery(obj any) error {
|
||||||
|
qMap := make(map[string]string)
|
||||||
|
for key, val := range rctx.Request.URL.Query() {
|
||||||
|
if len(val) == 1 {
|
||||||
|
qMap[key] = val[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bindObj(obj, qMap, "param")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response
|
||||||
|
func (rctx *Context) SetHeader(key, value string) {
|
||||||
|
rctx.Writer.Header().Set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) SetStatus(httpStatus int) {
|
||||||
|
rctx.StatusCode = httpStatus
|
||||||
|
rctx.Writer.WriteHeader(httpStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) SendJSON(statusCode int, payload any) {
|
||||||
|
rctx.StatusCode = statusCode
|
||||||
|
buffer := bytes.NewBuffer(nil)
|
||||||
|
json.NewEncoder(buffer).Encode(payload)
|
||||||
|
rctx.Writer.Header().Set("Content-Type", "application/json")
|
||||||
|
size := strconv.FormatInt(int64(len(buffer.Bytes())), 10)
|
||||||
|
rctx.Writer.Header().Set("Content-Length", size)
|
||||||
|
rctx.Writer.WriteHeader(statusCode)
|
||||||
|
rctx.Writer.Write(buffer.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) SendText(statusCode int, payload string) {
|
||||||
|
rctx.StatusCode = statusCode
|
||||||
|
size := strconv.FormatInt(int64(len(payload)), 10)
|
||||||
|
rctx.Writer.Header().Set("Content-Type", "text/plain")
|
||||||
|
rctx.Writer.Header().Set("Content-Length", size)
|
||||||
|
rctx.Writer.WriteHeader(statusCode)
|
||||||
|
rctx.Writer.Write([]byte(payload))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rctx *Context) SendBytes(statusCode int, ctype string, payload []byte) {
|
||||||
|
rctx.StatusCode = statusCode
|
||||||
|
size := strconv.FormatInt(int64(len(payload)), 10)
|
||||||
|
rctx.Writer.Header().Set("Content-Type", ctype)
|
||||||
|
rctx.Writer.Header().Set("Content-Length", size)
|
||||||
|
rctx.Writer.WriteHeader(statusCode)
|
||||||
|
rctx.Writer.Write(payload)
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package router
|
||||||
|
|
||||||
|
func NewCorsMiddleware() MiddlewareFunc {
|
||||||
|
mw := func(next Handler) Handler {
|
||||||
|
return newCorsHandler(next)
|
||||||
|
}
|
||||||
|
return mw
|
||||||
|
}
|
||||||
|
|
||||||
|
type corsHandler struct {
|
||||||
|
next Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCorsHandler(next Handler) *corsHandler {
|
||||||
|
return &corsHandler{
|
||||||
|
next: next,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand corsHandler) ServeHTTP(ctx *Context) {
|
||||||
|
origin := ctx.Request.Header.Get("Origin")
|
||||||
|
if origin != "" {
|
||||||
|
ctx.SetHeader("Access-Control-Allow-Origin", origin)
|
||||||
|
ctx.SetHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE, PATCH")
|
||||||
|
ctx.SetHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
||||||
|
ctx.SetHeader("Access-Control-Max-Age", "86400")
|
||||||
|
ctx.SetHeader("Access-Control-Allow-Credentials", "true")
|
||||||
|
}
|
||||||
|
if ctx.Request.Method == "OPTIONS" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hand.next.ServeHTTP(ctx)
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package router
|
||||||
|
|
||||||
|
func NewLoggingMiddleware(print func(string, ...any)) MiddlewareFunc {
|
||||||
|
mw := func(next Handler) Handler {
|
||||||
|
return newLoggingHandler(next, print)
|
||||||
|
}
|
||||||
|
return mw
|
||||||
|
}
|
||||||
|
|
||||||
|
type loggingHandler struct {
|
||||||
|
next Handler
|
||||||
|
printFunc func(string, ...any)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLoggingHandler(next Handler, print func(string, ...any)) *loggingHandler {
|
||||||
|
return &loggingHandler{
|
||||||
|
next: next,
|
||||||
|
printFunc: print,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (logging loggingHandler) ServeHTTP(rctx *Context) {
|
||||||
|
logging.next.ServeHTTP(rctx)
|
||||||
|
cl := rctx.Writer.Header().Get("Content-Length")
|
||||||
|
logging.printFunc("%s %s %s %s %s %d", rctx.Request.RemoteAddr,
|
||||||
|
rctx.Request.Method, rctx.Request.URL.String(),
|
||||||
|
rctx.Request.Proto, cl, rctx.StatusCode)
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
compContextPlain int = iota
|
||||||
|
compContextRegex
|
||||||
|
|
||||||
|
startRegex byte = '{'
|
||||||
|
stopRegex byte = '}'
|
||||||
|
)
|
||||||
|
|
||||||
|
func pathCompiler(path string) (string, error) {
|
||||||
|
var err error
|
||||||
|
res := make([]byte, 0)
|
||||||
|
var pos int = compContextPlain
|
||||||
|
var depth int = 0
|
||||||
|
pattern := make([]byte, 0)
|
||||||
|
for _, b := range []byte(path) {
|
||||||
|
switch pos {
|
||||||
|
case compContextPlain:
|
||||||
|
switch b {
|
||||||
|
case stopRegex:
|
||||||
|
depth -= 1
|
||||||
|
res = append(res, b)
|
||||||
|
case startRegex:
|
||||||
|
depth += 1
|
||||||
|
pos = compContextRegex // pattern started
|
||||||
|
pattern = make([]byte, 0)
|
||||||
|
default:
|
||||||
|
res = append(res, b)
|
||||||
|
}
|
||||||
|
case compContextRegex:
|
||||||
|
switch b {
|
||||||
|
case startRegex:
|
||||||
|
depth += 1
|
||||||
|
case stopRegex:
|
||||||
|
depth -= 1
|
||||||
|
if depth == 0 {
|
||||||
|
pattern = convertRegexp(pattern)
|
||||||
|
res = append(res, pattern...)
|
||||||
|
pos = compContextPlain // pattern ended
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
pattern = append(pattern, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if depth != 0 {
|
||||||
|
err = fmt.Errorf("Unbalanced brackets into pattern")
|
||||||
|
}
|
||||||
|
return string(res), err
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultRegexp = `[a-zA-Z0-9_\.*][/\-\.,a-zA-Z0-9_%=*\[\]:~\$]+`
|
||||||
|
)
|
||||||
|
|
||||||
|
func convertRegexp(src []byte) []byte {
|
||||||
|
var res string
|
||||||
|
const patternSeps = ":"
|
||||||
|
parts := strings.SplitN(string(src), patternSeps, 2)
|
||||||
|
if len(parts) == 1 {
|
||||||
|
parts = append(parts, defaultRegexp)
|
||||||
|
}
|
||||||
|
res = fmt.Sprintf("(?<%s>%s)", parts[0], parts[1])
|
||||||
|
return []byte(res)
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func tDebugf(msg string, args ...any) {
|
||||||
|
fmt.Printf("debug: ")
|
||||||
|
fmt.Printf(msg, args...)
|
||||||
|
fmt.Printf("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPatchCompilerA(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
srcPath := `/v1/file/{collection:[a-zA-Z]+}/{name}`
|
||||||
|
reSource, err := pathCompiler(srcPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tDebugf("re: %s\n", reSource)
|
||||||
|
|
||||||
|
re, err := regexp.Compile(reSource)
|
||||||
|
require.NoError(t, err)
|
||||||
|
reqPath := `/v1/file/foo/bare`
|
||||||
|
match := re.MatchString(reqPath)
|
||||||
|
require.True(t, match)
|
||||||
|
|
||||||
|
submatch := re.FindStringSubmatch(reqPath)
|
||||||
|
subnames := re.SubexpNames()
|
||||||
|
|
||||||
|
submap := make(map[string]string)
|
||||||
|
for i, val := range subnames {
|
||||||
|
tDebugf("subname: %d = %s", i, val)
|
||||||
|
}
|
||||||
|
for i, val := range submatch {
|
||||||
|
key := subnames[i]
|
||||||
|
if key != "" {
|
||||||
|
submap[key] = val
|
||||||
|
}
|
||||||
|
tDebugf("sub: %d = %s", i, val)
|
||||||
|
}
|
||||||
|
tDebugf("submap: %v", submap)
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"runtime/debug"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewRecoveryMiddleware(print func(string, ...any)) MiddlewareFunc {
|
||||||
|
mw := func(next Handler) Handler {
|
||||||
|
return newRecoveryHandler(next, print)
|
||||||
|
}
|
||||||
|
return mw
|
||||||
|
}
|
||||||
|
|
||||||
|
type recoveryHandler struct {
|
||||||
|
next Handler
|
||||||
|
print func(string, ...any)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRecoveryHandler(next Handler, print func(string, ...any)) *recoveryHandler {
|
||||||
|
return &recoveryHandler{
|
||||||
|
next: next,
|
||||||
|
print: print,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand recoveryHandler) ServeHTTP(rctx *Context) {
|
||||||
|
exitFunc := func() {
|
||||||
|
err := recover()
|
||||||
|
if err != nil {
|
||||||
|
rctx.Writer.WriteHeader(http.StatusInternalServerError)
|
||||||
|
stack := string(debug.Stack())
|
||||||
|
timestamp := time.Now().Format(time.RFC3339)
|
||||||
|
hand.print("%s %v ; %s\n", timestamp, err, stack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer exitFunc()
|
||||||
|
hand.next.ServeHTTP(rctx)
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MiddlewareFunc func(next Handler) Handler
|
||||||
|
|
||||||
|
type Handler interface {
|
||||||
|
ServeHTTP(rctx *Context)
|
||||||
|
}
|
||||||
|
|
||||||
|
type HandlerFunc func(rctx *Context)
|
||||||
|
|
||||||
|
func (handlerFunc HandlerFunc) ServeHTTP(rctx *Context) {
|
||||||
|
handlerFunc(rctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Router struct {
|
||||||
|
headHandler Handler
|
||||||
|
routeHandler *Selector
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRouter() *Router {
|
||||||
|
selector := NewSelector()
|
||||||
|
return &Router{
|
||||||
|
routeHandler: selector,
|
||||||
|
headHandler: selector,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rout *Router) Use(mwFunc MiddlewareFunc) {
|
||||||
|
rout.headHandler = mwFunc(rout.headHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rout *Router) Selector() *Selector {
|
||||||
|
return rout.routeHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rout *Router) AddRoute(method, path string, handlerFunc HandlerFunc) {
|
||||||
|
rout.routeHandler.AddRoute(method, path, handlerFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rout *Router) Head(path string, handlerFunc HandlerFunc) {
|
||||||
|
rout.routeHandler.AddRoute("HEAD", path, handlerFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rout *Router) Get(path string, handlerFunc HandlerFunc) {
|
||||||
|
rout.routeHandler.AddRoute("GET", path, handlerFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rout *Router) Post(path string, handlerFunc HandlerFunc) {
|
||||||
|
rout.routeHandler.AddRoute("POST", path, handlerFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rout *Router) Put(path string, handlerFunc HandlerFunc) {
|
||||||
|
rout.routeHandler.AddRoute("PUT", path, handlerFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rout *Router) Patch(path string, handlerFunc HandlerFunc) {
|
||||||
|
rout.routeHandler.AddRoute("PATCH", path, handlerFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rout *Router) Delete(path string, handlerFunc HandlerFunc) {
|
||||||
|
rout.routeHandler.AddRoute("DELETE", path, handlerFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rout *Router) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
|
||||||
|
rctx := NewContext(writer, req)
|
||||||
|
rout.headHandler.ServeHTTP(rctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rout *Router) NotFound(handlerFunc HandlerFunc) {
|
||||||
|
rout.routeHandler.notFound = handlerFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
type Selector struct {
|
||||||
|
Routes []*Route
|
||||||
|
notFound Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSelector() *Selector {
|
||||||
|
notFound := HandlerFunc(func(ctx *Context) {
|
||||||
|
http.NotFound(ctx.Writer, ctx.Request)
|
||||||
|
})
|
||||||
|
return &Selector{
|
||||||
|
Routes: make([]*Route, 0),
|
||||||
|
notFound: notFound,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const globalRoutePattern = `^%s$`
|
||||||
|
|
||||||
|
func (hand *Selector) AddRoute(method, path string, handlerFunc HandlerFunc) error {
|
||||||
|
var err error
|
||||||
|
rawPath := path
|
||||||
|
path, err = pathCompiler(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
path = fmt.Sprintf(globalRoutePattern, path)
|
||||||
|
re, err := regexp.Compile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
route := &Route{
|
||||||
|
Method: method,
|
||||||
|
Path: path,
|
||||||
|
RawPath: rawPath,
|
||||||
|
Handler: handlerFunc,
|
||||||
|
Regexp: re,
|
||||||
|
}
|
||||||
|
hand.Routes = append(hand.Routes, route)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hand *Selector) ServeHTTP(rctx *Context) {
|
||||||
|
realHandler := hand.notFound
|
||||||
|
for _, route := range hand.Routes {
|
||||||
|
match := route.Match(rctx.Request)
|
||||||
|
if !match {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
subvals := route.Regexp.FindStringSubmatch(rctx.Request.URL.Path)
|
||||||
|
subkeys := route.Regexp.SubexpNames()
|
||||||
|
for i, val := range subvals {
|
||||||
|
key := subkeys[i]
|
||||||
|
if key != "" {
|
||||||
|
rctx.PathMap[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
realHandler = route.Handler
|
||||||
|
break
|
||||||
|
}
|
||||||
|
realHandler.ServeHTTP(rctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Route struct {
|
||||||
|
Method string
|
||||||
|
Regexp *regexp.Regexp
|
||||||
|
Path string
|
||||||
|
RawPath string
|
||||||
|
Handler HandlerFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (route Route) Match(req *http.Request) bool {
|
||||||
|
if req.Method != route.Method {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
match := route.Regexp.MatchString(req.URL.Path)
|
||||||
|
if match {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRouterStatus(t *testing.T) {
|
||||||
|
|
||||||
|
reqPath := "/hello"
|
||||||
|
handler := NewRouter()
|
||||||
|
helloHandler := func(rctx *Context) {
|
||||||
|
rctx.SetStatus(http.StatusOK)
|
||||||
|
}
|
||||||
|
handler.Get(reqPath, helloHandler)
|
||||||
|
|
||||||
|
request, err := http.NewRequest("GET", reqPath, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(recorder, request)
|
||||||
|
require.Equal(t, http.StatusOK, recorder.Code)
|
||||||
|
|
||||||
|
fmt.Printf("Response code: %d\n", recorder.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouterSendText(t *testing.T) {
|
||||||
|
testText := "hello, world"
|
||||||
|
reqPath := "/hello"
|
||||||
|
rout := NewRouter()
|
||||||
|
helloHandler := func(rctx *Context) {
|
||||||
|
rctx.SendText(http.StatusOK, testText)
|
||||||
|
}
|
||||||
|
rout.Get(reqPath, helloHandler)
|
||||||
|
|
||||||
|
request, err := http.NewRequest("GET", reqPath, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
rout.ServeHTTP(recorder, request)
|
||||||
|
fmt.Printf("Response code: %d\n", recorder.Code)
|
||||||
|
require.Equal(t, http.StatusOK, recorder.Code)
|
||||||
|
|
||||||
|
bodyReader := recorder.Body
|
||||||
|
bodyBytes, err := io.ReadAll(bodyReader)
|
||||||
|
|
||||||
|
fmt.Printf("Response body: %s\n", string(bodyBytes))
|
||||||
|
require.Equal(t, string(bodyBytes), testText)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouterSendJSON(t *testing.T) {
|
||||||
|
|
||||||
|
type testStruct struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Code int64 `json:"code"`
|
||||||
|
}
|
||||||
|
testVar := testStruct{
|
||||||
|
Message: "hello, world",
|
||||||
|
Code: 123,
|
||||||
|
}
|
||||||
|
testData, err := json.Marshal(testVar)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
reqPath := "/hello"
|
||||||
|
handler := NewRouter()
|
||||||
|
|
||||||
|
helloHandler := func(rctx *Context) {
|
||||||
|
rctx.SendJSON(http.StatusOK, &testVar)
|
||||||
|
}
|
||||||
|
handler.Get(reqPath, helloHandler)
|
||||||
|
|
||||||
|
request, err := http.NewRequest("GET", reqPath, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(recorder, request)
|
||||||
|
fmt.Printf("Response code: %d\n", recorder.Code)
|
||||||
|
require.Equal(t, http.StatusOK, recorder.Code)
|
||||||
|
|
||||||
|
bodyReader := recorder.Body
|
||||||
|
bodyBytes, err := io.ReadAll(bodyReader)
|
||||||
|
require.NoError(t, err)
|
||||||
|
bodyBytes = bytes.Trim(bodyBytes, "\n\r")
|
||||||
|
|
||||||
|
fmt.Printf("Response body: %s\n", string(bodyBytes))
|
||||||
|
require.Equal(t, string(testData), string(bodyBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouterBindJSON(t *testing.T) {
|
||||||
|
|
||||||
|
type testStruct struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Code int64 `json:code"`
|
||||||
|
}
|
||||||
|
testVar := testStruct{
|
||||||
|
Message: "hello, world",
|
||||||
|
Code: 123,
|
||||||
|
}
|
||||||
|
testData, err := json.Marshal(testVar)
|
||||||
|
require.NoError(t, err)
|
||||||
|
buffer := bytes.NewBuffer(testData)
|
||||||
|
|
||||||
|
reqPath := "/hello"
|
||||||
|
handler := NewRouter()
|
||||||
|
|
||||||
|
helloHandler := func(rctx *Context) {
|
||||||
|
handVar := testStruct{}
|
||||||
|
rctx.BindJSON(&handVar)
|
||||||
|
fmt.Printf("Received message: %s - %d\n", handVar.Message, handVar.Code)
|
||||||
|
require.Equal(t, handVar.Code, int64(123))
|
||||||
|
rctx.SendJSON(http.StatusOK, &handVar)
|
||||||
|
}
|
||||||
|
handler.Post(reqPath, helloHandler)
|
||||||
|
|
||||||
|
request, err := http.NewRequest("POST", reqPath, buffer)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(recorder, request)
|
||||||
|
|
||||||
|
fmt.Printf("Response code: %d\n", recorder.Code)
|
||||||
|
require.Equal(t, http.StatusOK, recorder.Code)
|
||||||
|
|
||||||
|
bodyReader := recorder.Body
|
||||||
|
bodyBytes, err := io.ReadAll(bodyReader)
|
||||||
|
require.NoError(t, err)
|
||||||
|
bodyBytes = bytes.Trim(bodyBytes, "\n\r")
|
||||||
|
|
||||||
|
fmt.Printf("Response body: %s\n", string(bodyBytes))
|
||||||
|
require.Equal(t, string(testData), string(bodyBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouterBindParams(t *testing.T) {
|
||||||
|
|
||||||
|
reqPath := "/hello"
|
||||||
|
handler := NewRouter()
|
||||||
|
|
||||||
|
helloHandler := func(rctx *Context) {
|
||||||
|
type Params struct {
|
||||||
|
Name string `param:"name"`
|
||||||
|
Code int64 `param:"code"`
|
||||||
|
}
|
||||||
|
params := &Params{}
|
||||||
|
rctx.BindQuery(params)
|
||||||
|
fmt.Printf("Received name: %s\n", params.Name)
|
||||||
|
fmt.Printf("Received code: %d\n", params.Code)
|
||||||
|
rctx.SendText(http.StatusOK, "hello")
|
||||||
|
}
|
||||||
|
handler.Get(reqPath, helloHandler)
|
||||||
|
|
||||||
|
reqPath = reqPath + `?name=world&code=123`
|
||||||
|
request, err := http.NewRequest("GET", reqPath, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(recorder, request)
|
||||||
|
|
||||||
|
fmt.Printf("Response code: %d\n", recorder.Code)
|
||||||
|
require.Equal(t, http.StatusOK, recorder.Code)
|
||||||
|
|
||||||
|
bodyReader := recorder.Body
|
||||||
|
bodyBytes, err := io.ReadAll(bodyReader)
|
||||||
|
require.NoError(t, err)
|
||||||
|
bodyBytes = bytes.Trim(bodyBytes, "\n\r")
|
||||||
|
|
||||||
|
fmt.Printf("Response body: %s\n", string(bodyBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLoggerL(b *testing.B) {
|
||||||
|
reqPath := "/hello"
|
||||||
|
helloHandler := func(rctx *Context) {
|
||||||
|
rctx.SetStatus(http.StatusOK)
|
||||||
|
}
|
||||||
|
handler := NewRouter()
|
||||||
|
handler.Get(reqPath, helloHandler)
|
||||||
|
|
||||||
|
request, err := http.NewRequest("GET", reqPath, nil)
|
||||||
|
require.NoError(b, err)
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(recorder, request)
|
||||||
|
require.Equal(b, http.StatusOK, recorder.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
const protocol = "tcp"
|
||||||
|
|
||||||
|
func CreateTLSListener(addrinfo string, x509cert, x509key []byte) (net.Listener, error) {
|
||||||
|
var listen net.Listener
|
||||||
|
var err error
|
||||||
|
tlsCert, err := tls.X509KeyPair(x509cert, x509key)
|
||||||
|
if err != nil {
|
||||||
|
return listen, err
|
||||||
|
}
|
||||||
|
tlsConfig := tls.Config{
|
||||||
|
Certificates: []tls.Certificate{tlsCert},
|
||||||
|
ClientAuth: tls.NoClientCert,
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
}
|
||||||
|
listen, err = tls.Listen(protocol, addrinfo, &tlsConfig)
|
||||||
|
if err != nil {
|
||||||
|
return listen, err
|
||||||
|
}
|
||||||
|
return listen, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateListener(addrinfo string) (net.Listener, error) {
|
||||||
|
var listen net.Listener
|
||||||
|
var err error
|
||||||
|
listen, err = net.Listen(protocol, addrinfo)
|
||||||
|
if err != nil {
|
||||||
|
return listen, err
|
||||||
|
}
|
||||||
|
return listen, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,547 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"mbase/app/config"
|
||||||
|
"mbase/app/handler"
|
||||||
|
"mbase/app/logger"
|
||||||
|
"mbase/app/maindb"
|
||||||
|
"mbase/app/service"
|
||||||
|
"mbase/pkg/auxtool"
|
||||||
|
"mbase/pkg/descr"
|
||||||
|
|
||||||
|
"mbase/app/accoper"
|
||||||
|
"mbase/app/servoper"
|
||||||
|
|
||||||
|
yaml "go.yaml.in/yaml/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
conf *config.Config
|
||||||
|
acop *accoper.Operator
|
||||||
|
seop *servoper.Operator
|
||||||
|
svc *service.Service
|
||||||
|
mdb *maindb.Database
|
||||||
|
hand *handler.Handler
|
||||||
|
logg *logger.Logger
|
||||||
|
stat descr.Server
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
wg sync.WaitGroup
|
||||||
|
logf *os.File
|
||||||
|
//x509cert []byte
|
||||||
|
//x509key []byte
|
||||||
|
listen net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer() (*Server, error) {
|
||||||
|
var err error
|
||||||
|
srv := &Server{}
|
||||||
|
srv.logg = logger.NewLoggerWithSubject("server")
|
||||||
|
srv.ctx, srv.cancel = context.WithCancel(context.Background())
|
||||||
|
return srv, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) Handler() *handler.Handler {
|
||||||
|
return srv.hand
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) Service() *service.Service {
|
||||||
|
return srv.svc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) SetLogdir(dir string) {
|
||||||
|
srv.conf.Logpath = dir
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) SetRundir(dir string) {
|
||||||
|
srv.conf.Runpath = dir
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) SetDatadir(dir string) {
|
||||||
|
srv.conf.Database.Basepath = dir
|
||||||
|
srv.conf.Storage.Basepath = dir
|
||||||
|
srv.conf.Datadir = dir
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) SetPort(port uint32) {
|
||||||
|
srv.conf.Service.Port = port
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) SetAsDaemon(asDaemon bool) {
|
||||||
|
srv.conf.AsDaemon = asDaemon
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) Configure() error {
|
||||||
|
var err error
|
||||||
|
//srv.logg.Infof("Configuration server")
|
||||||
|
srv.conf = config.NewConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = srv.conf.ReadConfigfile()
|
||||||
|
if err != nil {
|
||||||
|
srv.logg.Warningf("Error loading config file: %v", err)
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
err = srv.conf.ReadX509Cert()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) writeStat() error {
|
||||||
|
// Write status file
|
||||||
|
var err error
|
||||||
|
statefilePath := filepath.Join(srv.conf.Datadir, "server.yaml")
|
||||||
|
stateData, err := yaml.Marshal(srv.stat)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(statefilePath, stateData, 0640)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) readStat() error {
|
||||||
|
var err error
|
||||||
|
// Read state file
|
||||||
|
statefilePath := filepath.Join(srv.conf.Datadir, "server.yaml")
|
||||||
|
if auxtool.FileExists(statefilePath) {
|
||||||
|
stateData, err := ioutil.ReadFile(statefilePath)
|
||||||
|
if err == nil {
|
||||||
|
stat := descr.Server{}
|
||||||
|
err = yaml.Unmarshal(stateData, &stat)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srv.stat = stat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) Build() error {
|
||||||
|
var err error
|
||||||
|
//srv.logg.Infof("Server building")
|
||||||
|
|
||||||
|
currUser, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error getting current user: %v\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cuid64, err := strconv.ParseInt(currUser.Uid, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cgid64, err := strconv.ParseInt(currUser.Gid, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
euid := int(cuid64)
|
||||||
|
egid := int(cgid64)
|
||||||
|
if cuid64 == 0 {
|
||||||
|
usr, err := user.Lookup(srv.conf.RunUser)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
uid64, err := strconv.ParseInt(usr.Uid, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
gid64, err := strconv.ParseInt(usr.Gid, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
euid = int(uid64)
|
||||||
|
egid = int(gid64)
|
||||||
|
}
|
||||||
|
// Creating datadir
|
||||||
|
datadir := srv.conf.Datadir
|
||||||
|
if !auxtool.DirExists(datadir) { // TODO: check access to dir
|
||||||
|
//srv.logg.Infof("Creating data directory %s ", datadir)
|
||||||
|
err = os.MkdirAll(datadir, 0750)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = os.Chown(datadir, euid, egid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if srv.conf.AsDaemon {
|
||||||
|
logdir := filepath.Dir(srv.conf.Logpath)
|
||||||
|
//srv.logg.Infof("Creating log directory %s", logdir)
|
||||||
|
err = os.MkdirAll(logdir, 0750)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.Chown(logdir, euid, egid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rundir := filepath.Dir(srv.conf.Runpath)
|
||||||
|
//srv.logg.Infof("Creating run directory %s", rundir)
|
||||||
|
err = os.MkdirAll(rundir, 0750)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.Chown(rundir, euid, egid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Redirect stderr and stout
|
||||||
|
logFile, err := os.OpenFile(srv.conf.Logpath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0640)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = syscall.Dup2(int(logFile.Fd()), int(os.Stdout.Fd()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = syscall.Dup2(int(logFile.Fd()), int(os.Stderr.Fd()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srv.logf = logFile
|
||||||
|
}
|
||||||
|
|
||||||
|
confDump := srv.conf.String()
|
||||||
|
srv.logg.Infof("Current server configuration is:\n%s\n", confDump)
|
||||||
|
|
||||||
|
// Read state file
|
||||||
|
srv.logg.Infof("Reading server status")
|
||||||
|
err = srv.readStat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Creating database dir
|
||||||
|
dbdir := srv.conf.Database.Basepath
|
||||||
|
srv.logg.Infof("Creating database directory %s ", dbdir)
|
||||||
|
err = os.MkdirAll(dbdir, 0750)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Creating storage dir
|
||||||
|
srv.logg.Infof("Creating storage directory")
|
||||||
|
datadir = srv.conf.Database.Basepath
|
||||||
|
err = os.MkdirAll(datadir, 0750)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.Chown(datadir, euid, egid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cert, key := []byte(srv.conf.X509Cert), []byte(srv.conf.X509Key)
|
||||||
|
addrinfo := fmt.Sprintf("%s:%d", srv.conf.Service.Address, srv.conf.Service.Port)
|
||||||
|
listener, err := CreateTLSListener(addrinfo, cert, key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srv.listen = listener
|
||||||
|
|
||||||
|
if cuid64 == 0 {
|
||||||
|
// Change effective user and group
|
||||||
|
err = syscall.Setgid(egid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = syscall.Setuid(euid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//return fmt.Errorf("Debug break")
|
||||||
|
|
||||||
|
uidstr := strconv.FormatInt(int64(syscall.Geteuid()), 10)
|
||||||
|
usr, err := user.LookupId(uidstr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srv.logg.Warningf("Now run as user: %s", usr.Username)
|
||||||
|
// Creating database
|
||||||
|
mdb := maindb.NewDatabase(dbdir)
|
||||||
|
srv.logg.Infof("Opening main database")
|
||||||
|
err = mdb.OpenDatabase()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srv.mdb = mdb
|
||||||
|
|
||||||
|
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
// Created db scheme
|
||||||
|
if !srv.stat.SchemeCreated {
|
||||||
|
srv.logg.Infof("Initialize main database")
|
||||||
|
err = mdb.InitDatabase()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srv.stat.SchemeCreated = true
|
||||||
|
srv.stat.SchemeCreatedAt = auxtool.TimeNow()
|
||||||
|
srv.logg.Infof("Writing server status")
|
||||||
|
err = srv.writeStat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Created anonymous user
|
||||||
|
if !srv.stat.AnonymousCreated {
|
||||||
|
srv.logg.Infof("Creating anonymous user")
|
||||||
|
err = mdb.WriteAnonymous(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srv.stat.AnonymousCreated = true
|
||||||
|
srv.stat.AnonymousCreatedAt = auxtool.TimeNow()
|
||||||
|
srv.logg.Infof("Writing server status")
|
||||||
|
err = srv.writeStat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !srv.stat.InituserCreated {
|
||||||
|
srv.logg.Infof("Creating init user")
|
||||||
|
err = srv.mdb.WriteInituser(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srv.stat.InituserCreatedAt = auxtool.TimeNow()
|
||||||
|
srv.stat.InituserCreated = true
|
||||||
|
|
||||||
|
srv.logg.Infof("Writing server status")
|
||||||
|
err = srv.writeStat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creating account operator
|
||||||
|
srv.logg.Infof("Creating account operator")
|
||||||
|
accoperParams := &accoper.OperatorParams{
|
||||||
|
MainDB: srv.mdb,
|
||||||
|
}
|
||||||
|
srv.acop, err = accoper.NewOperator(accoperParams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Creating service operator
|
||||||
|
srv.logg.Infof("Creating operator")
|
||||||
|
servoperParams := &servoper.OperatorParams{
|
||||||
|
MainDB: srv.mdb,
|
||||||
|
}
|
||||||
|
srv.seop, err = servoper.NewOperator(servoperParams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Creating handler
|
||||||
|
srv.logg.Infof("Creating handler")
|
||||||
|
handlerParams := &handler.HandlerParams{
|
||||||
|
MainDB: srv.mdb,
|
||||||
|
AccOper: srv.acop,
|
||||||
|
ServOper: srv.seop,
|
||||||
|
}
|
||||||
|
srv.hand, err = handler.NewHandler(handlerParams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Creating service
|
||||||
|
serviceParams := &service.ServiceParams{
|
||||||
|
Handler: srv.hand,
|
||||||
|
Listener: srv.listen,
|
||||||
|
}
|
||||||
|
srv.logg.Infof("Creating service")
|
||||||
|
srv.svc, err = service.NewService(serviceParams)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Building service
|
||||||
|
err = srv.svc.Build()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) Run() error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if srv.conf.AsDaemon {
|
||||||
|
// Redirect stdin
|
||||||
|
nullFile, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = syscall.Dup2(int(nullFile.Fd()), int(os.Stdin.Fd()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Write process ID
|
||||||
|
pidFile, err := os.OpenFile(srv.conf.Runpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer pidFile.Close()
|
||||||
|
currPid := os.Getpid()
|
||||||
|
_, err = pidFile.WriteString(strconv.Itoa(currPid))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Start log rotator
|
||||||
|
srv.Rotator()
|
||||||
|
}
|
||||||
|
|
||||||
|
currUser, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srv.logg.Infof("Server started with user: %s", currUser.Username)
|
||||||
|
uidstr := strconv.FormatInt(int64(syscall.Geteuid()), 10)
|
||||||
|
usr, err := user.LookupId(uidstr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srv.logg.Infof("Server run with user: %s", usr.Username)
|
||||||
|
|
||||||
|
svcDone := make(chan error, 1)
|
||||||
|
// Service run
|
||||||
|
srv.logg.Infof("Start service")
|
||||||
|
startService := func(svc *service.Service, done chan error) {
|
||||||
|
err = svc.Run()
|
||||||
|
if err != nil {
|
||||||
|
srv.logg.Errorf("Service error: %v", err)
|
||||||
|
done <- err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go startService(srv.svc, svcDone)
|
||||||
|
|
||||||
|
sigs := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
var signal os.Signal
|
||||||
|
|
||||||
|
select {
|
||||||
|
case signal = <-sigs:
|
||||||
|
srv.logg.Infof("Services stopped by signal: %v", signal)
|
||||||
|
srv.cancel()
|
||||||
|
srv.svc.Stop()
|
||||||
|
srv.wg.Wait()
|
||||||
|
case err = <-svcDone:
|
||||||
|
srv.logg.Infof("Service stopped by service error: %v", err)
|
||||||
|
srv.cancel()
|
||||||
|
srv.svc.Stop()
|
||||||
|
srv.wg.Wait()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) PseudoFork() error {
|
||||||
|
const successExit int = 0
|
||||||
|
var keyEnv string = "IMX0LTSELMRF8K"
|
||||||
|
var err error
|
||||||
|
|
||||||
|
_, isChild := os.LookupEnv(keyEnv)
|
||||||
|
switch {
|
||||||
|
case !isChild:
|
||||||
|
os.Setenv(keyEnv, "TRUE")
|
||||||
|
|
||||||
|
procAttr := syscall.ProcAttr{}
|
||||||
|
cwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var sysFiles = make([]uintptr, 3)
|
||||||
|
sysFiles[0] = uintptr(syscall.Stdin)
|
||||||
|
sysFiles[1] = uintptr(syscall.Stdout)
|
||||||
|
sysFiles[2] = uintptr(syscall.Stderr)
|
||||||
|
|
||||||
|
procAttr.Files = sysFiles
|
||||||
|
procAttr.Env = os.Environ()
|
||||||
|
procAttr.Dir = cwd
|
||||||
|
|
||||||
|
_, err = syscall.ForkExec(os.Args[0], os.Args, &procAttr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
os.Exit(successExit)
|
||||||
|
case isChild:
|
||||||
|
_, err = syscall.Setsid()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os.Unsetenv(keyEnv)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) Daemonize() error {
|
||||||
|
var err error
|
||||||
|
if srv.conf.AsDaemon {
|
||||||
|
// Restart process process
|
||||||
|
err = srv.PseudoFork()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srv *Server) Rotator() {
|
||||||
|
srv.wg.Add(1)
|
||||||
|
var counter uint64
|
||||||
|
logFunc := func() {
|
||||||
|
for {
|
||||||
|
counter += 1
|
||||||
|
select {
|
||||||
|
case <-srv.ctx.Done():
|
||||||
|
srv.wg.Done()
|
||||||
|
srv.logg.Infof("Log file rotator done")
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if (counter % 60) == 1 {
|
||||||
|
stat, err := srv.logf.Stat()
|
||||||
|
if err == nil && stat.Size() > srv.conf.LogLimit {
|
||||||
|
srv.logg.Infof("Rotate log file")
|
||||||
|
countFiles := 3
|
||||||
|
for i := 1; i < countFiles; i++ {
|
||||||
|
nextName := fmt.Sprintf("%s.%d", srv.conf.Logpath, i+1)
|
||||||
|
prevName := fmt.Sprintf("%s.%d", srv.conf.Logpath, i)
|
||||||
|
os.Rename(prevName, nextName)
|
||||||
|
}
|
||||||
|
os.Rename(srv.conf.Logpath, srv.conf.Logpath+".1")
|
||||||
|
logFile, err := os.OpenFile(srv.conf.Logpath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0640)
|
||||||
|
if err == nil {
|
||||||
|
syscall.Dup2(int(logFile.Fd()), int(os.Stdout.Fd()))
|
||||||
|
syscall.Dup2(int(logFile.Fd()), int(os.Stderr.Fd()))
|
||||||
|
srv.logf.Close()
|
||||||
|
srv.logf = logFile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go logFunc()
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"mbase/app/handler"
|
||||||
|
"mbase/app/logger"
|
||||||
|
"mbase/app/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServiceParams struct {
|
||||||
|
Handler *handler.Handler
|
||||||
|
Listener net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
hand *handler.Handler
|
||||||
|
rout *router.Router
|
||||||
|
logg *logger.Logger
|
||||||
|
listen net.Listener
|
||||||
|
hsrv *http.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(params *ServiceParams) (*Service, error) {
|
||||||
|
var err error
|
||||||
|
svc := &Service{
|
||||||
|
hand: params.Handler,
|
||||||
|
listen: params.Listener,
|
||||||
|
}
|
||||||
|
svc.logg = logger.NewLoggerWithSubject("service")
|
||||||
|
return svc, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *Service) Build() error {
|
||||||
|
var err error
|
||||||
|
svc.logg.Infof("Service build ")
|
||||||
|
|
||||||
|
svc.rout = router.NewRouter()
|
||||||
|
|
||||||
|
svc.rout.Use(router.NewRecoveryMiddleware(svc.logg.Errorf))
|
||||||
|
svc.rout.Use(router.NewLoggingMiddleware(svc.logg.Infof))
|
||||||
|
svc.rout.Use(router.NewCorsMiddleware())
|
||||||
|
svc.rout.Use(svc.hand.AuthMiddleware)
|
||||||
|
|
||||||
|
svc.rout.Get(`/v3/api/service/hello`, svc.hand.SendHello)
|
||||||
|
|
||||||
|
svc.rout.Post(`/v3/api/account/create`, svc.hand.CreateAccount)
|
||||||
|
svc.rout.Post(`/v3/api/account/get`, svc.hand.GetAccount)
|
||||||
|
svc.rout.Post(`/v3/api/account/update`, svc.hand.UpdateAccount)
|
||||||
|
svc.rout.Post(`/v3/api/account/delete`, svc.hand.DeleteAccount)
|
||||||
|
svc.rout.Post(`/v3/api/accounts/list`, svc.hand.ListAccounts)
|
||||||
|
|
||||||
|
svc.rout.Post(`/v3/api/grant/create`, svc.hand.CreateGrant)
|
||||||
|
svc.rout.Post(`/v3/api/grant/get`, svc.hand.GetGrant)
|
||||||
|
svc.rout.Post(`/v3/api/grant/update`, svc.hand.UpdateGrant)
|
||||||
|
svc.rout.Post(`/v3/api/grant/delete`, svc.hand.DeleteGrant)
|
||||||
|
svc.rout.Post(`/v3/api/grants/list`, svc.hand.ListGrants)
|
||||||
|
|
||||||
|
svc.rout.NotFound(svc.hand.NotFound)
|
||||||
|
|
||||||
|
selector := svc.rout.Selector()
|
||||||
|
for _, item := range selector.Routes {
|
||||||
|
svc.logg.Infof("%s\t%s", item.Method, item.RawPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.logg.Infof("Service listening at %v", svc.listen.Addr())
|
||||||
|
svc.hsrv = &http.Server{
|
||||||
|
Handler: svc.rout,
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *Service) Run() error {
|
||||||
|
var err error
|
||||||
|
svc.logg.Infof("Service run")
|
||||||
|
err = svc.hsrv.Serve(svc.listen)
|
||||||
|
if err == http.ErrServerClosed {
|
||||||
|
svc.logg.Warningf("Service Closed")
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *Service) Stop() {
|
||||||
|
if svc.hsrv != nil {
|
||||||
|
svc.logg.Infof("Service stop")
|
||||||
|
downWaiting := 10 * time.Second
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), downWaiting)
|
||||||
|
defer cancel()
|
||||||
|
err := svc.hsrv.Shutdown(ctx)
|
||||||
|
if err != nil {
|
||||||
|
svc.logg.Errorf("Error service shutdown: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package servoper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mbase/app/logger"
|
||||||
|
"mbase/app/maindb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OperatorParams struct {
|
||||||
|
MainDB *maindb.Database
|
||||||
|
}
|
||||||
|
|
||||||
|
type Operator struct {
|
||||||
|
mdb *maindb.Database
|
||||||
|
logg *logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOperator(params *OperatorParams) (*Operator, error) {
|
||||||
|
var err error
|
||||||
|
oper := &Operator{
|
||||||
|
mdb: params.MainDB,
|
||||||
|
}
|
||||||
|
oper.logg = logger.NewLoggerWithSubject("servoper")
|
||||||
|
return oper, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
|
||||||
|
*/
|
||||||
|
package servoper
|
||||||
|
|
||||||
|
type SendHelloParams struct{}
|
||||||
|
|
||||||
|
type SendHelloResult struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Alive bool `json:"alive"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oper *Operator) SendHello(param *SendHelloParams) (*SendHelloResult, error) {
|
||||||
|
var err error
|
||||||
|
res := &SendHelloResult{
|
||||||
|
Alive: true,
|
||||||
|
Message: "hello",
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
*~
|
||||||
|
Chart.yaml
|
||||||
|
values.yaml
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
*.in
|
||||||
|
*~
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
name: @PACKAGE_NAME@
|
||||||
|
description: mbase service
|
||||||
|
type: application
|
||||||
|
version: "@PACKAGE_VERSION@"
|
||||||
|
appVersion: "@PACKAGE_VERSION@"
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{{- define "mstore.imagePath" -}}
|
||||||
|
{{- if .Values.global -}}
|
||||||
|
{{- if .Values.global.imagePath -}}
|
||||||
|
{{- .Values.global.imagePath -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- .Values.main.image.path -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{{- define "mstore.servicePort" -}}
|
||||||
|
{{- if .Values.global -}}
|
||||||
|
{{- if .Values.global.mstorePort -}}
|
||||||
|
{{- .Values.global.mstorePort -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- .Values.main.service.port -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{{- define "mstore.storageClass" -}}
|
||||||
|
{{- if .Values.global -}}
|
||||||
|
{{- if .Values.global.storageClass -}}
|
||||||
|
{{- .Values.global.storageClass -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- .Values.main.storageClass -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{{- define "mstore.storageSize" -}}
|
||||||
|
{{- if .Values.global -}}
|
||||||
|
{{- if .Values.global.mstoreStorageSize -}}
|
||||||
|
{{- .Values.global.mstoreStorageSize -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- .Values.main.storageSize -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{{- define "mstore.username" -}}
|
||||||
|
{{- if .Values.global -}}
|
||||||
|
{{- if .Values.global.mstoreUsername -}}
|
||||||
|
{{- .Values.global.mstoreUsername -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- fail "Istore username is empty, fill it in global values.yaml !" -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- if .Values.main.auth.username -}}
|
||||||
|
{{- .Values.main.auth.username -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- fail "Istore username is empty, fill it in values.yaml !" -}}
|
||||||
|
{{- end }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "mstore.password" -}}
|
||||||
|
{{- if .Values.global -}}
|
||||||
|
{{- if .Values.global.mstoreUserpass -}}
|
||||||
|
{{- .Values.global.mstoreUserpass -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- fail "Istore password is empty, fill it in global values.yaml !"}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- if .Values.main.auth.password -}}
|
||||||
|
{{- .Values.main.auth.password -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- fail "Istore password is empty, fill it in values.yaml !"}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
name: mstored-config
|
||||||
|
data:
|
||||||
|
mstored.yaml: |-
|
||||||
|
service:
|
||||||
|
address: 0.0.0.0
|
||||||
|
port: {{ include "mstore.servicePort" . }}
|
||||||
|
asDaemon: false
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: mstore
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mstore
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: mstore
|
||||||
|
spec:
|
||||||
|
restartPolicy: Always
|
||||||
|
containers:
|
||||||
|
- securityContext:
|
||||||
|
privileged: true
|
||||||
|
image: {{ include "mstore.imagePath" . }}/{{ .Values.main.image.name }}:{{ .Values.main.image.tag }}
|
||||||
|
imagePullPolicy: {{ .Values.main.image.imagePullPolicy }}
|
||||||
|
name: mstore
|
||||||
|
ports:
|
||||||
|
- containerPort: {{ include "mstore.servicePort" . }}
|
||||||
|
protocol: TCP
|
||||||
|
volumeMounts:
|
||||||
|
- name: config-volume
|
||||||
|
mountPath: /app/etc/mstore
|
||||||
|
# - name: db-volume
|
||||||
|
# mountPath: /var/lib
|
||||||
|
volumes:
|
||||||
|
- name: config-volume
|
||||||
|
configMap:
|
||||||
|
name: mstored-config
|
||||||
|
# - name: db-volume
|
||||||
|
# persistentVolumeClaim:
|
||||||
|
# claimName: mstore-data
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: mstore
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: mstore
|
||||||
|
ports:
|
||||||
|
- port: {{ include "mstore.servicePort" . }}
|
||||||
|
protocol: TCP
|
||||||
|
targetPort: {{ include "mstore.servicePort" . }}
|
||||||
|
name: api
|
||||||
|
type: {{ .Values.main.service.type }}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
main:
|
||||||
|
image:
|
||||||
|
path: t14x.unix7.org/mstore
|
||||||
|
name: "@PACKAGE_NAME@"
|
||||||
|
tag: "@PACKAGE_VERSION@"
|
||||||
|
imagePullPolicy: Always
|
||||||
|
service:
|
||||||
|
type: LoadBalancer
|
||||||
|
port: 1025
|
||||||
|
# x509Cert: xxx
|
||||||
|
# x509Key: xxx
|
||||||
|
hostname: "localhost"
|
||||||
|
daemon: false
|
||||||
|
storageClass: local-path
|
||||||
|
storageSize: 10Gi
|
||||||
|
|
||||||
+1815
File diff suppressed because it is too large
Load Diff
+2354
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+258
@@ -0,0 +1,258 @@
|
|||||||
|
AC_INIT([mbase],[0.2.5])
|
||||||
|
AM_INIT_AUTOMAKE([foreign subdir-objects tar-pax])
|
||||||
|
AC_PREFIX_DEFAULT(/usr/local)
|
||||||
|
|
||||||
|
PACKAGE=mstore
|
||||||
|
|
||||||
|
AC_CHECK_PROG(HAVE_GO, go, true, false)
|
||||||
|
if test "x$HAVE_GO" = "xfalse"; then
|
||||||
|
AC_MSG_ERROR([Requested program go not found])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_PATH_PROG([GO],[go])
|
||||||
|
AC_PATH_PROG([FIND],[find])
|
||||||
|
AC_PATH_PROG([XARGS],[xargs])
|
||||||
|
AC_PATH_PROG([SORT],[sort])
|
||||||
|
AC_PATH_PROG([UNIQ],[uniq])
|
||||||
|
AC_PATH_PROGS([SUDO],[sudo false])
|
||||||
|
AC_PATH_PROGS([CPIO],[cpio false])
|
||||||
|
AC_PATH_PROGS([BASENAME],[basename])
|
||||||
|
|
||||||
|
AC_PATH_PROGS([PODMAN],[podman true])
|
||||||
|
AC_PATH_PROGS([HELM],[helm true])
|
||||||
|
AC_PATH_PROGS([DBUILDPACKAGE],[dpkg-buildpackage true])
|
||||||
|
AC_PATH_PROGS([DPKGSOURCE],[dpkg-source true])
|
||||||
|
AC_PATH_PROGS([SWAG],[swag true])
|
||||||
|
|
||||||
|
|
||||||
|
AC_PATH_PROGS([CP],[gcp cp])
|
||||||
|
if test -z "$CP"; then
|
||||||
|
AC_MSG_ERROR([Requested program cp not found])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
AC_PROG_MKDIR_P
|
||||||
|
AC_CANONICAL_HOST
|
||||||
|
|
||||||
|
case $host_os in
|
||||||
|
*freebsd* )
|
||||||
|
AC_SUBST(ROOT_GROUP, "wheel")
|
||||||
|
AM_CONDITIONAL(FREEBSD_OS, true)
|
||||||
|
AM_CONDITIONAL(LINUX_OS, false)
|
||||||
|
OSNAME=freebsd
|
||||||
|
ROOT_GROUP=wheel
|
||||||
|
;;
|
||||||
|
*linux* )
|
||||||
|
AC_SUBST(ROOT_GROUP, "root")
|
||||||
|
AM_CONDITIONAL(FREEBSD_OS, false)
|
||||||
|
AM_CONDITIONAL(LINUX_OS, true)
|
||||||
|
OSNAME=linux
|
||||||
|
ROOT_GROUP=root
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
AM_CONDITIONAL(SYSTEMD, false)
|
||||||
|
if test -d /lib/systemd/system; then
|
||||||
|
AM_CONDITIONAL(SYSTEMD, true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
test "x$prefix" == "xNONE" && prefix=$ac_default_prefix
|
||||||
|
test "x$libexecdir" == "xNONE" && libexecdir=${prefix}/lib
|
||||||
|
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
AC_ARG_ENABLE([devel-mode],
|
||||||
|
AS_HELP_STRING([--enable-devel-mode], [Enable developmend mode]))
|
||||||
|
|
||||||
|
|
||||||
|
AC_DEFINE_UNQUOTED(srv_devel_mode, "false", [developmend mode])
|
||||||
|
AC_SUBST(srv_devel_mode, "false")
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_devel_mode" = "xyes"], [
|
||||||
|
SRCDIR=`pwd`
|
||||||
|
enable_devel_mode=yes
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SRV_CONFDIR="${prefix}/etc/${PACKAGE}"
|
||||||
|
|
||||||
|
AC_ARG_WITH(confdir,
|
||||||
|
AS_HELP_STRING([--with-confdir=PATH],[set configuration dir to PATH (default: $SRV_CONFDIR)]),
|
||||||
|
[ if test ! -z "$withval" ; then
|
||||||
|
case $withval in
|
||||||
|
/*)
|
||||||
|
SRV_CONFDIR="$withval"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR(You must specify an absolute path to --with-confdir=PATH)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi ])
|
||||||
|
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_devel_mode" = "xyes"], [
|
||||||
|
SRV_CONFDIR="${SRCDIR}/etc/${PACKAGE}"
|
||||||
|
sysconfdir="${SRCDIR}/etc/${PACKAGE}"
|
||||||
|
], [
|
||||||
|
test "x$SRV_CONFDIR" == "x/usr/etc/${PACKAGE}" && SRV_CONFDIR="/etc/${PACKAGE}"
|
||||||
|
test "x$prefix" == "x/usr" && sysconfdir="/etc"
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFINE_UNQUOTED(SRV_CONFDIR, "$SRV_CONFDIR", [location of configuration files for ${PACKAGE}])
|
||||||
|
AC_SUBST(srv_confdir, "$SRV_CONFDIR")
|
||||||
|
|
||||||
|
AC_MSG_NOTICE(srv_confdir set as ${SRV_CONFDIR})
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SRV_LOGDIR="/var/log/${PACKAGE}"
|
||||||
|
|
||||||
|
AC_ARG_WITH(logdir,
|
||||||
|
AS_HELP_STRING([--with-logdir=PATH],[set path for logdir (default: $SRV_LOGDIR)]),
|
||||||
|
[ if test ! -z "$withval" ; then
|
||||||
|
case $withval in
|
||||||
|
/*)
|
||||||
|
SRV_LOGDIR="$withval"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR(You must specify an absolute path to --with-logdir=PATH)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_devel_mode" = "xyes"], [
|
||||||
|
SRV_LOGDIR="${SRCDIR}/tmp/log"
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFINE_UNQUOTED(SRV_LOGDIR, "$SRV_LOGDIR", [location of ${PACKAGE} logdir])
|
||||||
|
AC_SUBST(srv_logdir, "$SRV_LOGDIR")
|
||||||
|
|
||||||
|
AC_MSG_NOTICE(srv_logdir set as ${SRV_LOGDIR})
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SRV_RUNDIR="/var/run/${PACKAGE}"
|
||||||
|
|
||||||
|
AC_ARG_WITH(rundir,
|
||||||
|
AS_HELP_STRING([--with-rundir=PATH],[set path for rundir (default: $SRV_RUNDIR)]),
|
||||||
|
[ if test ! -z "$withval" ; then
|
||||||
|
case $withval in
|
||||||
|
/*)
|
||||||
|
SRV_RUNDIR="$withval"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR(You must specify an absolute path to --with-rundir=PATH)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi ])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_devel_mode" = "xyes"], [
|
||||||
|
SRV_RUNDIR="${SRCDIR}/tmp/run"
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
AC_DEFINE_UNQUOTED(SRV_RUNDIR, "$SRV_RUNDIR", [location of rundir])
|
||||||
|
AC_SUBST(srv_rundir, "$SRV_RUNDIR")
|
||||||
|
|
||||||
|
AC_MSG_NOTICE(srv_rundir set as ${SRV_RUNDIR})
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SRV_SHAREDIR="${prefix}/share/$PACKAGE"
|
||||||
|
|
||||||
|
AC_ARG_WITH(sharedir,
|
||||||
|
AS_HELP_STRING([--with-sharedir=PATH],[set share directory (default: $SRV_SHAREDIR)]),
|
||||||
|
[ if test ! -z "$with_sharedir" ; then
|
||||||
|
case $with_sharedir in
|
||||||
|
/*)
|
||||||
|
SRV_SHAREDIR="$withval"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR(You must specify an absolute path to --with-sharedir=PATH)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi ])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_devel_mode" = "xyes"], [
|
||||||
|
SRV_SHAREDIR="${SRCDIR}/share"
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
AC_DEFINE_UNQUOTED(SRV_SHAREDIR, "$SRV_SHAREDIR", [location of share dir])
|
||||||
|
AC_SUBST(srv_sharedir, "$SRV_SHAREDIR")
|
||||||
|
|
||||||
|
AC_MSG_NOTICE(srv_sharedir set as ${SRV_SHAREDIR})
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SRV_LIBDIR="${prefix}/lib/$PACKAGE"
|
||||||
|
|
||||||
|
AC_ARG_WITH(libdir,
|
||||||
|
AS_HELP_STRING([--with-libdir=PATH],[set lib directory (default: $SRV_LIBDIR)]),
|
||||||
|
[ if test ! -z "$withval" ; then
|
||||||
|
case $withval in
|
||||||
|
/*)
|
||||||
|
SRV_LIBDIR="$withval"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR(You must specify an absolute path to --with-libdir=PATH)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi ])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_devel_mode" = "xyes"], [
|
||||||
|
SRV_LIBDIR="${SRCDIR}/sysagent"
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFINE_UNQUOTED(SRV_LIBDIR, "$SRV_LIBDIR", [location of lib dir])
|
||||||
|
AC_SUBST(srv_libdir, "$SRV_LIBDIR")
|
||||||
|
|
||||||
|
AC_MSG_NOTICE(srv_libdir set as ${SRV_LIBDIR})
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
SRV_DATADIR="/var/lib/${PACKAGE}"
|
||||||
|
|
||||||
|
AC_ARG_WITH(datadir,
|
||||||
|
AS_HELP_STRING([--with-datadir=PATH],[set path for datadir (default: $SRV_DATADIR)]),
|
||||||
|
[ if test ! -z "$withval" ; then
|
||||||
|
case $withval in
|
||||||
|
/*)
|
||||||
|
SRV_DATADIR="$withval"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR(You must specify an absolute path to --with-datadir=PATH)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi])
|
||||||
|
|
||||||
|
AS_IF([test "x$enable_devel_mode" = "xyes"], [
|
||||||
|
SRV_DATADIR="${SRCDIR}/tmp/data"
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFINE_UNQUOTED(SRV_DATADIR, "$SRV_DATADIR", [location of ${PACKAGE} datadir])
|
||||||
|
AC_SUBST(srv_datadir, "$SRV_DATADIR")
|
||||||
|
|
||||||
|
AC_MSG_NOTICE(srv_datadir set as ${SRV_DATADIR})
|
||||||
|
|
||||||
|
dnl --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
AM_EXTRA_RECURSIVE_TARGETS([docs])
|
||||||
|
|
||||||
|
AC_CONFIG_FILES([
|
||||||
|
Makefile
|
||||||
|
app/config/variant.go
|
||||||
|
initrc/mstored.service
|
||||||
|
initrc/mstored
|
||||||
|
chart/Chart.yaml
|
||||||
|
chart/values.yaml
|
||||||
|
debian/control
|
||||||
|
debian/changelog
|
||||||
|
mans/Makefile
|
||||||
|
])
|
||||||
|
AC_OUTPUT
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
changelog
|
||||||
|
control
|
||||||
|
*~
|
||||||
|
tmp
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
mbase for Debian
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
mbase (@PACKAGE_VERSION@-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Release.
|
||||||
|
|
||||||
|
-- Oleg Borodin <borodin@unix7.org> Sun, 29 Oct 2017 18:57:56 +0200
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
10
|
||||||
Vendored
+15
@@ -0,0 +1,15 @@
|
|||||||
|
Source: mbase
|
||||||
|
Section: utils
|
||||||
|
Priority: extra
|
||||||
|
Maintainer: borodin@unix7.org
|
||||||
|
Build-Depends: debhelper (>=8)
|
||||||
|
Standards-Version: @PACKAGE_VERSION@
|
||||||
|
Homepage: http://wiki.unix7.org
|
||||||
|
|
||||||
|
Package: mbase-control
|
||||||
|
Description: mbase
|
||||||
|
Architecture: amd64
|
||||||
|
|
||||||
|
Package: mbase-service
|
||||||
|
Description: mbase
|
||||||
|
Architecture: amd64
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
mstore-control-dbgsym_2.11.0-1_amd64.deb debug optional automatic=yes
|
||||||
|
mstore-control_2.11.0-1_amd64.deb utils extra
|
||||||
|
mstore-service-dbgsym_2.11.0-1_amd64.deb debug optional automatic=yes
|
||||||
|
mstore-service_2.11.0-1_amd64.deb utils extra
|
||||||
|
mstore_2.11.0-1_amd64.buildinfo utils extra
|
||||||
Vendored
+2
@@ -0,0 +1,2 @@
|
|||||||
|
usr/bin/mstorectl
|
||||||
|
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
install|upgrade)
|
||||||
|
;;
|
||||||
|
|
||||||
|
abort-upgrade)
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "preinst called with unknown argument \`$1'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
#DEBHELPER#
|
||||||
|
|
||||||
|
exit 0
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
usr/sbin/mstored
|
||||||
|
lib/systemd/system/mstored.service
|
||||||
|
var/run/mstore
|
||||||
|
var/log/mstore
|
||||||
|
etc/mstore
|
||||||
|
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
if [ "$1" = "configure" ] ; then
|
||||||
|
# Initial installation
|
||||||
|
systemctl preset mstored.service >/dev/null 2>&1 || :
|
||||||
|
fi
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
systemctl daemon-reload >/dev/null 2>&1 || :
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
install|upgrade)
|
||||||
|
;;
|
||||||
|
|
||||||
|
abort-upgrade)
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "preinst called with unknown argument \`$1'" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
|
||||||
|
#DEBHELPER#
|
||||||
|
|
||||||
|
exit 0
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
if [ "$1" = "remove" ] || [ "$1" = "purge" ]; then
|
||||||
|
# Package removal, not upgrade
|
||||||
|
systemctl --no-reload disable mstored.service > /dev/null 2>&1 || :
|
||||||
|
systemctl stop mstored.service > /dev/null 2>&1 || :
|
||||||
|
fi
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
# You must remove unused comment lines for the released package.
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
export GO111MODULE=on
|
||||||
|
export GOPROXY=https://proxy.golang.org
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@
|
||||||
|
|
||||||
|
override_dh_auto_configure:
|
||||||
|
./configure --prefix=/usr
|
||||||
|
|
||||||
|
|
||||||
|
#EOF
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
3.0 (quilt)
|
||||||
Vendored
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
version=3
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
MimeType: application/vnd.oci.image.manifest.v1+json
|
||||||
|
|
||||||
|
{
|
||||||
|
"schemaVersion": 2,
|
||||||
|
"config": {
|
||||||
|
"mediaType": "application/vnd.cncf.helm.config.v1+json",
|
||||||
|
"digest": "sha256:33e3759271a3c6dc018541cfb73653c267df6f8ee28ce68e38c72e22196a1d87",
|
||||||
|
"size": 126
|
||||||
|
},
|
||||||
|
"layers": [{
|
||||||
|
"mediaType": "application/vnd.cncf.helm.chart.content.v1.tar+gzip",
|
||||||
|
"digest": "sha256:93dc97d49c453a7ce3af622cf7ef698548045e0c09907c6a021018f6eac6c31a",
|
||||||
|
"size": 1528
|
||||||
|
}],
|
||||||
|
"annotations": {
|
||||||
|
"org.opencontainers.image.created": "2026-02-25T19:59:44+02:00",
|
||||||
|
"org.opencontainers.image.description": "mStore service",
|
||||||
|
"org.opencontainers.image.title": "mstore",
|
||||||
|
"org.opencontainers.image.version": "0.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/27.0.9 Chrome/134.0.6998.205 Electron/35.4.0 Safari/537.36" version="27.0.9">
|
||||||
|
<diagram name="Page-1" id="bilFRRFyBUGthtbaxYIo">
|
||||||
|
<mxGraphModel dx="1880" dy="566" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" background="#ffffff" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="0" />
|
||||||
|
<mxCell id="1" parent="0" />
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-28" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#F0FDFF;glass=0;strokeColor=#0e8088;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="-10" y="55" width="120" height="335" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-26" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#F0FDFF;glass=0;strokeColor=#0e8088;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="120" y="50" width="630" height="350" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-5" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;curved=0;" edge="1" parent="1" source="t6Klk0bs08zzC_b7PXua-1" target="t6Klk0bs08zzC_b7PXua-2">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-30" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;curved=0;exitX=0.75;exitY=0;exitDx=0;exitDy=0;" edge="1" parent="1" source="t6Klk0bs08zzC_b7PXua-2" target="t6Klk0bs08zzC_b7PXua-29">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-2" value="service" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="250" y="230" width="80" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-11" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;curved=0;strokeColor=#000099;exitX=0.75;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="t6Klk0bs08zzC_b7PXua-3" target="t6Klk0bs08zzC_b7PXua-8">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-19" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;strokeColor=#0000CC;curved=0;" edge="1" parent="1" source="t6Klk0bs08zzC_b7PXua-20" target="t6Klk0bs08zzC_b7PXua-17">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-3" value="handler" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#b1ddf0;strokeColor=#10739e;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="390" y="150" width="90" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-7" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.75;entryDx=0;entryDy=0;curved=0;strokeColor=#000099;" edge="1" parent="1" source="t6Klk0bs08zzC_b7PXua-6" target="t6Klk0bs08zzC_b7PXua-2">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-6" value="client" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#fad7ac;strokeColor=#b46504;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="10" y="240" width="90" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-12" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;curved=0;strokeColor=#000099;" edge="1" parent="1" source="t6Klk0bs08zzC_b7PXua-8" target="t6Klk0bs08zzC_b7PXua-9">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-18" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;curved=0;" edge="1" parent="1" source="t6Klk0bs08zzC_b7PXua-8" target="t6Klk0bs08zzC_b7PXua-17">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-23" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;curved=0;" edge="1" parent="1" source="t6Klk0bs08zzC_b7PXua-8" target="t6Klk0bs08zzC_b7PXua-10">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-8" value="operator" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#b1ddf0;strokeColor=#10739e;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="500" y="230" width="90" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-9" value="storage" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#b0e3e6;strokeColor=#0e8088;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="570" y="300" width="90" height="50" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-10" value="lockers" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#bac8d3;strokeColor=#23445d;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="550" y="150" width="70" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-16" value="starter" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="140" y="110" width="80" height="50" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-33" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.25;exitDx=0;exitDy=0;curved=0;" edge="1" parent="1" source="t6Klk0bs08zzC_b7PXua-1" target="t6Klk0bs08zzC_b7PXua-32">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-1" value="server" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="150" y="145" width="80" height="55" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-17" value="database" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#b0e3e6;strokeColor=#0e8088;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="630" y="220" width="90" height="50" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-20" value="auth" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#b1ddf0;strokeColor=#10739e;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="420" y="120" width="50" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-31" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;curved=0;" edge="1" parent="1" source="t6Klk0bs08zzC_b7PXua-29" target="t6Klk0bs08zzC_b7PXua-3">
|
||||||
|
<mxGeometry relative="1" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-29" value="router" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#b1ddf0;strokeColor=#10739e;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="290" y="140" width="70" height="50" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-32" value="config" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#b0e3e6;strokeColor=#0e8088;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="290" y="70" width="70" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="t6Klk0bs08zzC_b7PXua-34" value="Feb 2026<div>O Borodin</div>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;strokeColor=default;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="510" y="430" width="110" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
</mxfile>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 2,
|
||||||
|
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||||
|
"config": {
|
||||||
|
"mediaType": "application/vnd.oci.image.config.v1+json",
|
||||||
|
"digest": "sha256:2f99832d1fc23ae7c8a35d5aa0b9d7a78a1876d69f9453d5d6e8701ac86c171c",
|
||||||
|
"size": 1357
|
||||||
|
},
|
||||||
|
"layers": [{
|
||||||
|
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||||
|
"digest": "sha256:7319607d119c259e90382101fb3ed98ad62e29ed817338183b3775dcfb358140",
|
||||||
|
"size": 3731518
|
||||||
|
}, {
|
||||||
|
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||||
|
"digest": "sha256:1fccc5cb3c84a43c9dec4d89f1383471b41e1c4b9d4f271e3c952839f76634f5",
|
||||||
|
"size": 15791440
|
||||||
|
}, {
|
||||||
|
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
|
||||||
|
"digest": "sha256:8cc3f2f15e1a38f6b733038dd9b3b27a88d4882a78a3235416f792dd9deca7af",
|
||||||
|
"size": 173
|
||||||
|
}],
|
||||||
|
"annotations": {
|
||||||
|
"com.docker.official-images.bashbrew.arch": "amd64",
|
||||||
|
"org.opencontainers.image.base.digest": "sha256:b0cb30c51c47cdfde647364301758b14c335dea2fddc9490d4f007d67ecb2538",
|
||||||
|
"org.opencontainers.image.base.name": "docker.io/library/alpine:3.20",
|
||||||
|
"org.opencontainers.image.created": "2026-01-28T01:18:13Z",
|
||||||
|
"org.opencontainers.image.revision": "b3f87708e5052e29737a251b2e9865e182dafe0c",
|
||||||
|
"org.opencontainers.image.source": "https://github.com/alpinelinux/docker-alpine.git#b3f87708e5052e29737a251b2e9865e182dafe0c:x86_64",
|
||||||
|
"org.opencontainers.image.url": "https://hub.docker.com/_/alpine",
|
||||||
|
"org.opencontainers.image.version": "3.20.9"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEojCCBCmgAwIBAgISBpbPr7WFeCJ3U8QDioKGHkQiMAoGCCqGSM49BAMDMDIx
|
||||||
|
CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF
|
||||||
|
ODAeFw0yNjAyMTIwOTExMDVaFw0yNjA1MTMwOTExMDRaMBgxFjAUBgNVBAMTDWRl
|
||||||
|
di51bml4Ny5vcmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATZnNwUA6M5kqmq
|
||||||
|
36oRkUTC+fSPlLiLDs3Vz6fPdYBWIokPKG+UqAS4WjfXXQEPwqGeoef0b5elB7dg
|
||||||
|
6GjwOhJio4IDNzCCAzMwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUF
|
||||||
|
BwMBMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFBme/mBwOaT6f4yzzCBc4i/NPQBY
|
||||||
|
MB8GA1UdIwQYMBaAFI8NE6L2Ln7RUGwzGDhdWY4jcpHKMDIGCCsGAQUFBwEBBCYw
|
||||||
|
JDAiBggrBgEFBQcwAoYWaHR0cDovL2U4LmkubGVuY3Iub3JnLzCCATUGA1UdEQSC
|
||||||
|
ASwwggEogg1haXIudW5peDcub3JnghJhaXJmb3JjZS51bml4Ny5vcmeCDWRldi51
|
||||||
|
bml4Ny5vcmeCDWVkdS51bml4Ny5vcmeCEGVkdW1heC51bml4Ny5vcmeCDWdpdC51
|
||||||
|
bml4Ny5vcmeCDWhhbS51bml4Ny5vcmeCDmhhc2gudW5peDcub3JnggxoZC51bml4
|
||||||
|
Ny5vcmeCDm1haWwudW5peDcub3Jnggxtdy51bml4Ny5vcmeCDG14LnVuaXg3Lm9y
|
||||||
|
Z4IOcGlraS51bml4Ny5vcmeCDHJtLnVuaXg3Lm9yZ4IQc3RvcmV4LnVuaXg3Lm9y
|
||||||
|
Z4INdzEyLnVuaXg3Lm9yZ4INdzEzLnVuaXg3Lm9yZ4IOd2lraS51bml4Ny5vcmeC
|
||||||
|
DXd3dy51bml4Ny5vcmcwEwYDVR0gBAwwCjAIBgZngQwBAgEwLQYDVR0fBCYwJDAi
|
||||||
|
oCCgHoYcaHR0cDovL2U4LmMubGVuY3Iub3JnLzM1LmNybDCCAQsGCisGAQQB1nkC
|
||||||
|
BAIEgfwEgfkA9wB1AGQRxGykEuyniRyiAi4AvKtPKAfUHjUnq+r+1QPJfc3wAAAB
|
||||||
|
nFFT2U0AAAQDAEYwRAIgbuNiYUqwgxi9Oycm2D6h8sclWLcBXHtqFWpwJT3dwbgC
|
||||||
|
IBBjMRcAmxZKE9PIgFqMvosPNQ7AAkbEfudVtqNkfwXJAH4Apcl4kl1XRheChw3Y
|
||||||
|
iWYLXFVki30AQPLsB2hR0YhpGfcAAAGcUVPcHQAIAAAFADH4c7UEAwBHMEUCIQDz
|
||||||
|
p9aYuw9jAZjxM8U3Qq7M4vFpp0GZDm80tpTdKYNjjwIgQ/e/lWg6uqQsjBytcaOG
|
||||||
|
IVXPEyB0n8fflOf+Ekh51DUwCgYIKoZIzj0EAwMDZwAwZAIwRrEAdYBcRU46Pold
|
||||||
|
w4VjUGnGsYEUqlsjrmn4awY01YGWknPaX5sTAI3hTuA32eOUAjA1dSANAAyO+icj
|
||||||
|
1ZiPZUGFjaMdkEu6Y/Ge8aueAUItNj9eF0ahlgZEnSlhHrswoZo=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP
|
||||||
|
MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy
|
||||||
|
Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa
|
||||||
|
Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF
|
||||||
|
bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c
|
||||||
|
S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb
|
||||||
|
R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB
|
||||||
|
9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB
|
||||||
|
MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j
|
||||||
|
cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB
|
||||||
|
BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE
|
||||||
|
DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j
|
||||||
|
ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0
|
||||||
|
RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d
|
||||||
|
AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8
|
||||||
|
otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA
|
||||||
|
aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm
|
||||||
|
Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2
|
||||||
|
HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1
|
||||||
|
Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR
|
||||||
|
xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d
|
||||||
|
tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/
|
||||||
|
jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS
|
||||||
|
u1igv3OefnWjSQ==
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEIOqwKQF1VWp3lSiIgD5E1ZNGXf/IlBLwEp8F+YooRiuGoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAE2ZzcFAOjOZKpqt+qEZFEwvn0j5S4iw7N1c+nz3WAViKJDyhvlKgE
|
||||||
|
uFo3110BD8KhnqHn9G+XpQe3YOho8DoSYg==
|
||||||
|
-----END EC PRIVATE KEY-----
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
certpath: mbased.crt
|
||||||
|
keypath: mbased.key
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
module mbase
|
||||||
|
|
||||||
|
go 1.25.7
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/dustin/go-humanize v1.0.1
|
||||||
|
github.com/google/go-containerregistry v0.21.3
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
|
github.com/jmoiron/sqlx v1.4.0
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.38
|
||||||
|
github.com/opencontainers/go-digest v1.0.0
|
||||||
|
github.com/opencontainers/image-spec v1.1.1
|
||||||
|
github.com/spf13/cobra v1.10.2
|
||||||
|
github.com/spf13/viper v1.21.0
|
||||||
|
github.com/stretchr/testify v1.11.1
|
||||||
|
go.yaml.in/yaml/v4 v4.0.0-rc.4
|
||||||
|
helm.sh/helm/v4 v4.1.3
|
||||||
|
sigs.k8s.io/yaml v1.6.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||||
|
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||||
|
github.com/Masterminds/semver/v3 v3.4.0 // indirect
|
||||||
|
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
||||||
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
|
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||||
|
github.com/cloudflare/circl v1.6.3 // indirect
|
||||||
|
github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
|
github.com/docker/cli v29.3.0+incompatible // indirect
|
||||||
|
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||||
|
github.com/docker/docker-credential-helpers v0.9.3 // indirect
|
||||||
|
github.com/dylibso/observe-sdk/go v0.0.0-20240819160327-2d926c5d788a // indirect
|
||||||
|
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
|
||||||
|
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
|
||||||
|
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||||
|
github.com/extism/go-sdk v1.7.1 // indirect
|
||||||
|
github.com/fluxcd/cli-utils v0.37.2-flux.1 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
|
||||||
|
github.com/go-errors/errors v1.5.1 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||||
|
github.com/go-openapi/swag v0.23.1 // indirect
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||||
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
|
github.com/gofrs/flock v0.13.0 // indirect
|
||||||
|
github.com/google/btree v1.1.3 // indirect
|
||||||
|
github.com/google/gnostic-models v0.7.0 // indirect
|
||||||
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20240805132620-81f5be970eca // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/compress v1.18.4 // indirect
|
||||||
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||||
|
github.com/mailru/easyjson v0.9.0 // indirect
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
|
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
|
github.com/moby/term v0.5.2 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
|
||||||
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
|
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.4 // indirect
|
||||||
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||||
|
github.com/spf13/afero v1.15.0 // indirect
|
||||||
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
|
github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834 // indirect
|
||||||
|
github.com/tetratelabs/wazero v1.11.0 // indirect
|
||||||
|
github.com/vbatts/tar-split v0.12.2 // indirect
|
||||||
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
|
github.com/xlab/treeprint v1.2.0 // indirect
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0 // indirect
|
||||||
|
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
|
golang.org/x/crypto v0.47.0 // indirect
|
||||||
|
golang.org/x/net v0.49.0 // indirect
|
||||||
|
golang.org/x/oauth2 v0.36.0 // indirect
|
||||||
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
|
golang.org/x/sys v0.42.0 // indirect
|
||||||
|
golang.org/x/term v0.39.0 // indirect
|
||||||
|
golang.org/x/text v0.33.0 // indirect
|
||||||
|
golang.org/x/time v0.12.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
|
||||||
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
gotest.tools/v3 v3.5.2 // indirect
|
||||||
|
k8s.io/api v0.35.1 // indirect
|
||||||
|
k8s.io/apiextensions-apiserver v0.35.1 // indirect
|
||||||
|
k8s.io/apimachinery v0.35.1 // indirect
|
||||||
|
k8s.io/cli-runtime v0.35.1 // indirect
|
||||||
|
k8s.io/client-go v0.35.1 // indirect
|
||||||
|
k8s.io/component-base v0.35.1 // indirect
|
||||||
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
|
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
|
||||||
|
k8s.io/kubectl v0.35.1 // indirect
|
||||||
|
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
|
||||||
|
oras.land/oras-go/v2 v2.6.0 // indirect
|
||||||
|
sigs.k8s.io/controller-runtime v0.23.1 // indirect
|
||||||
|
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
|
||||||
|
sigs.k8s.io/kustomize/api v0.21.1 // indirect
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.21.1 // indirect
|
||||||
|
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect
|
||||||
|
)
|
||||||
@@ -0,0 +1,384 @@
|
|||||||
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
|
||||||
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
|
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
||||||
|
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||||
|
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
|
||||||
|
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||||
|
github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw=
|
||||||
|
github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||||
|
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||||
|
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
|
||||||
|
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
|
||||||
|
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||||
|
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
|
||||||
|
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
|
||||||
|
github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
|
||||||
|
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||||
|
github.com/containerd/stargz-snapshotter/estargz v0.18.2 h1:yXkZFYIzz3eoLwlTUZKz2iQ4MrckBxJjkmD16ynUTrw=
|
||||||
|
github.com/containerd/stargz-snapshotter/estargz v0.18.2/go.mod h1:XyVU5tcJ3PRpkA9XS2T5us6Eg35yM0214Y+wvrZTBrY=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
|
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
|
||||||
|
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/distribution/distribution/v3 v3.0.0 h1:q4R8wemdRQDClzoNNStftB2ZAfqOiN6UX90KJc4HjyM=
|
||||||
|
github.com/distribution/distribution/v3 v3.0.0/go.mod h1:tRNuFoZsUdyRVegq8xGNeds4KLjwLCRin/tTo6i1DhU=
|
||||||
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
|
github.com/docker/cli v29.3.0+incompatible h1:z3iWveU7h19Pqx7alZES8j+IeFQZ1lhTwb2F+V9SVvk=
|
||||||
|
github.com/docker/cli v29.3.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
|
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||||
|
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
|
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
|
||||||
|
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
|
||||||
|
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
|
||||||
|
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
|
||||||
|
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
|
||||||
|
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
|
||||||
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
|
github.com/dylibso/observe-sdk/go v0.0.0-20240819160327-2d926c5d788a h1:UwSIFv5g5lIvbGgtf3tVwC7Ky9rmMFBp0RMs+6f6YqE=
|
||||||
|
github.com/dylibso/observe-sdk/go v0.0.0-20240819160327-2d926c5d788a/go.mod h1:C8DzXehI4zAbrdlbtOByKX6pfivJTBiV9Jjqv56Yd9Q=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
|
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
|
||||||
|
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
|
||||||
|
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
|
||||||
|
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
|
||||||
|
github.com/extism/go-sdk v1.7.1 h1:lWJos6uY+tRFdlIHR+SJjwFDApY7OypS/2nMhiVQ9Sw=
|
||||||
|
github.com/extism/go-sdk v1.7.1/go.mod h1:IT+Xdg5AZM9hVtpFUA+uZCJMge/hbvshl8bwzLtFyKA=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
|
github.com/fluxcd/cli-utils v0.37.2-flux.1 h1:tQ588ghtRN+E+kHq415FddfqA9v4brn/1WWgrP6rQR0=
|
||||||
|
github.com/fluxcd/cli-utils v0.37.2-flux.1/go.mod h1:LcWSu1NYET8d8U7O326RhEm5JkQXCMK6ITu4G1CT02c=
|
||||||
|
github.com/foxcpp/go-mockdns v1.2.0 h1:omK3OrHRD1IWJz1FuFBCFquhXslXoF17OvBS6JPzZF0=
|
||||||
|
github.com/foxcpp/go-mockdns v1.2.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||||
|
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
|
||||||
|
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||||
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
|
||||||
|
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
|
||||||
|
github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
|
||||||
|
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
|
||||||
|
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
|
||||||
|
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
|
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
|
github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
|
||||||
|
github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=
|
||||||
|
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||||
|
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
|
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
|
||||||
|
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/go-containerregistry v0.21.3 h1:Xr+yt3VvwOOn/5nJzd7UoOhwPGiPkYW0zWDLLUXqAi4=
|
||||||
|
github.com/google/go-containerregistry v0.21.3/go.mod h1:D5ZrJF1e6dMzvInpBPuMCX0FxURz7GLq2rV3Us9aPkc=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
|
||||||
|
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
|
||||||
|
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
|
||||||
|
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
|
||||||
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7 h1:X+2YciYSxvMQK0UZ7sg45ZVabVZBeBuvMkmuI2V3Fak=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.7/go.mod h1:lW34nIZuQ8UDPdkon5fmfp2l3+ZkQ2me/+oecHYLOII=
|
||||||
|
github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw=
|
||||||
|
github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20240805132620-81f5be970eca h1:T54Ema1DU8ngI+aef9ZhAhNGQhcRTrWxVeG07F+c/Rw=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20240805132620-81f5be970eca/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
||||||
|
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
||||||
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
|
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
|
||||||
|
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||||
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||||
|
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||||
|
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.38 h1:tDUzL85kMvOrvpCt8P64SbGgVFtJB11GPi2AdmITgb4=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.38/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
|
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
||||||
|
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||||
|
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||||
|
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
|
||||||
|
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
|
||||||
|
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
|
||||||
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
|
||||||
|
github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q=
|
||||||
|
github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
|
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||||
|
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
|
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
|
||||||
|
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||||
|
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||||
|
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||||
|
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||||
|
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
|
||||||
|
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||||
|
github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEoIwkU+A6qos=
|
||||||
|
github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=
|
||||||
|
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
|
||||||
|
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
|
||||||
|
github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho=
|
||||||
|
github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U=
|
||||||
|
github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc=
|
||||||
|
github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ=
|
||||||
|
github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
|
||||||
|
github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||||
|
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||||
|
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
|
||||||
|
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||||
|
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
|
||||||
|
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||||
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
||||||
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||||
|
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||||
|
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||||
|
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||||
|
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
|
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||||
|
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||||
|
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||||
|
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
|
github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834 h1:ZF+QBjOI+tILZjBaFj3HgFonKXUcwgJ4djLb6i42S3Q=
|
||||||
|
github.com/tetratelabs/wabin v0.0.0-20230304001439-f6f874872834/go.mod h1:m9ymHTgNSEjuxvw8E7WWe4Pl4hZQHXONY8wE6dMLaRk=
|
||||||
|
github.com/tetratelabs/wazero v1.11.0 h1:+gKemEuKCTevU4d7ZTzlsvgd1uaToIDtlQlmNbwqYhA=
|
||||||
|
github.com/tetratelabs/wazero v1.11.0/go.mod h1:eV28rsN8Q+xwjogd7f4/Pp4xFxO7uOGbLcD/LzB1wiU=
|
||||||
|
github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4=
|
||||||
|
github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
|
||||||
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
|
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
|
||||||
|
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
|
go.opentelemetry.io/contrib/bridges/prometheus v0.65.0 h1:I/7S/yWobR3QHFLqHsJ8QOndoiFsj1VgHpQiq43KlUI=
|
||||||
|
go.opentelemetry.io/contrib/bridges/prometheus v0.65.0/go.mod h1:jPF6gn3y1E+nozCAEQj3c6NZ8KY+tvAgSVfvoOJUFac=
|
||||||
|
go.opentelemetry.io/contrib/exporters/autoexport v0.65.0 h1:2gApdml7SznX9szEKFjKjM4qGcGSvAybYLBY319XG3g=
|
||||||
|
go.opentelemetry.io/contrib/exporters/autoexport v0.65.0/go.mod h1:0QqAGlbHXhmPYACG3n5hNzO5DnEqqtg4VcK5pr22RI0=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
|
||||||
|
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
|
||||||
|
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 h1:ZVg+kCXxd9LtAaQNKBxAvJ5NpMf7LpvEr4MIZqb0TMQ=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0/go.mod h1:hh0tMeZ75CCXrHd9OXRYxTlCAdxcXioWHFIpYw2rZu8=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0 h1:djrxvDxAe44mJUrKataUbOhCKhR3F8QCyWucO16hTQs=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0/go.mod h1:dt3nxpQEiSoKvfTVxp3TUg5fHPLhKtbcnN3Z1I1ePD0=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0 h1:NOyNnS19BF2SUDApbOKbDtWZ0IK7b8FJ2uAGdIWOGb0=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0/go.mod h1:VL6EgVikRLcJa9ftukrHu/ZkkhFBSo1lzvdBC9CF1ss=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0 h1:9y5sHvAxWzft1WQ4BwqcvA+IFVUJ1Ya75mSAUnFEVwE=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.40.0/go.mod h1:eQqT90eR3X5Dbs1g9YSM30RavwLF725Ris5/XSXWvqE=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 h1:wVZXIWjQSeSmMoxF74LzAnpVQOAFDo3pPji9Y4SOFKc=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40=
|
||||||
|
go.opentelemetry.io/otel/exporters/prometheus v0.62.0 h1:krvC4JMfIOVdEuNPTtQ0ZjCiXrybhv+uOHMfHRmnvVo=
|
||||||
|
go.opentelemetry.io/otel/exporters/prometheus v0.62.0/go.mod h1:fgOE6FM/swEnsVQCqCnbOfRV4tOnWPg7bVeo4izBuhQ=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.16.0 h1:ivlbaajBWJqhcCPniDqDJmRwj4lc6sRT+dCAVKNmxlQ=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.16.0/go.mod h1:u/G56dEKDDwXNCVLsbSrllB2o8pbtFLUC4HpR66r2dc=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0 h1:ZrPRak/kS4xI3AVXy8F7pipuDXmDsrO8Lg+yQjBLjw0=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.40.0/go.mod h1:3y6kQCWztq6hyW8Z9YxQDDm0Je9AJoFar2G0yDcmhRk=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0 h1:MzfofMZN8ulNqobCmCAVbqVL5syHw+eB2qPRkCMA/fQ=
|
||||||
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0/go.mod h1:E73G9UFtKRXrxhBsHtG00TB5WxX57lpsQzogDkqBTz8=
|
||||||
|
go.opentelemetry.io/otel/log v0.16.0 h1:DeuBPqCi6pQwtCK0pO4fvMB5eBq6sNxEnuTs88pjsN4=
|
||||||
|
go.opentelemetry.io/otel/log v0.16.0/go.mod h1:rWsmqNVTLIA8UnwYVOItjyEZDbKIkMxdQunsIhpUMes=
|
||||||
|
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
|
||||||
|
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
|
||||||
|
go.opentelemetry.io/otel/sdk/log v0.16.0 h1:e/b4bdlQwC5fnGtG3dlXUrNOnP7c8YLVSpSfEBIkTnI=
|
||||||
|
go.opentelemetry.io/otel/sdk/log v0.16.0/go.mod h1:JKfP3T6ycy7QEuv3Hj8oKDy7KItrEkus8XJE6EoSzw4=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
|
||||||
|
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
|
||||||
|
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||||
|
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
|
go.yaml.in/yaml/v4 v4.0.0-rc.4 h1:UP4+v6fFrBIb1l934bDl//mmnoIZEDK0idg1+AIvX5U=
|
||||||
|
go.yaml.in/yaml/v4 v4.0.0-rc.4/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
|
||||||
|
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
|
||||||
|
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
|
||||||
|
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||||
|
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||||
|
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
|
||||||
|
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
|
||||||
|
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||||
|
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
|
||||||
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
|
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
|
||||||
|
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
|
||||||
|
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
|
||||||
|
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
|
||||||
|
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||||
|
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||||
|
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||||
|
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
|
google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc=
|
||||||
|
google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U=
|
||||||
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=
|
||||||
|
gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
|
||||||
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
|
||||||
|
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
|
||||||
|
helm.sh/helm/v4 v4.1.3 h1:Abfmb+oJUtxoaXDyB2Jhw1zRk3hT6aFfHta+AXb8Lno=
|
||||||
|
helm.sh/helm/v4 v4.1.3/go.mod h1:5dSo8rRgn3OTkDAc/k0Ipw5/Q+BlqKIKZwa0XwSiINI=
|
||||||
|
k8s.io/api v0.35.1 h1:0PO/1FhlK/EQNVK5+txc4FuhQibV25VLSdLMmGpDE/Q=
|
||||||
|
k8s.io/api v0.35.1/go.mod h1:28uR9xlXWml9eT0uaGo6y71xK86JBELShLy4wR1XtxM=
|
||||||
|
k8s.io/apiextensions-apiserver v0.35.1 h1:p5vvALkknlOcAqARwjS20kJffgzHqwyQRM8vHLwgU7w=
|
||||||
|
k8s.io/apiextensions-apiserver v0.35.1/go.mod h1:2CN4fe1GZ3HMe4wBr25qXyJnJyZaquy4nNlNmb3R7AQ=
|
||||||
|
k8s.io/apimachinery v0.35.1 h1:yxO6gV555P1YV0SANtnTjXYfiivaTPvCTKX6w6qdDsU=
|
||||||
|
k8s.io/apimachinery v0.35.1/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
|
||||||
|
k8s.io/cli-runtime v0.35.1 h1:uKcXFe8J7AMAM4Gm2JDK4mp198dBEq2nyeYtO+JfGJE=
|
||||||
|
k8s.io/cli-runtime v0.35.1/go.mod h1:55/hiXIq1C8qIJ3WBrWxEwDLdHQYhBNRdZOz9f7yvTw=
|
||||||
|
k8s.io/client-go v0.35.1 h1:+eSfZHwuo/I19PaSxqumjqZ9l5XiTEKbIaJ+j1wLcLM=
|
||||||
|
k8s.io/client-go v0.35.1/go.mod h1:1p1KxDt3a0ruRfc/pG4qT/3oHmUj1AhSHEcxNSGg+OA=
|
||||||
|
k8s.io/component-base v0.35.1 h1:XgvpRf4srp037QWfGBLFsYMUQJkE5yMa94UsJU7pmcE=
|
||||||
|
k8s.io/component-base v0.35.1/go.mod h1:HI/6jXlwkiOL5zL9bqA3en1Ygv60F03oEpnuU1G56Bs=
|
||||||
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
|
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
|
||||||
|
k8s.io/kubectl v0.35.1 h1:zP3Er8C5i1dcAFUMh9Eva0kVvZHptXIn/+8NtRWMxwg=
|
||||||
|
k8s.io/kubectl v0.35.1/go.mod h1:cQ2uAPs5IO/kx8R5s5J3Ihv3VCYwrx0obCXum0CvnXo=
|
||||||
|
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
|
||||||
|
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
|
oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc=
|
||||||
|
oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o=
|
||||||
|
sigs.k8s.io/controller-runtime v0.23.1 h1:TjJSM80Nf43Mg21+RCy3J70aj/W6KyvDtOlpKf+PupE=
|
||||||
|
sigs.k8s.io/controller-runtime v0.23.1/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
|
||||||
|
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
|
||||||
|
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||||
|
sigs.k8s.io/kustomize/api v0.21.1 h1:lzqbzvz2CSvsjIUZUBNFKtIMsEw7hVLJp0JeSIVmuJs=
|
||||||
|
sigs.k8s.io/kustomize/api v0.21.1/go.mod h1:f3wkKByTrgpgltLgySCntrYoq5d3q7aaxveSagwTlwI=
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.21.1 h1:IVlbmhC076nf6foyL6Taw4BkrLuEsXUXNpsE+ScX7fI=
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.21.1/go.mod h1:hmxADesM3yUN2vbA5z1/YTBnzLJ1dajdqpQonwBL1FQ=
|
||||||
|
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
|
||||||
|
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 h1:2WOzJpHUBVrrkDjU4KBT8n5LDcj824eX0I5UKcgeRUs=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
|
||||||
|
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
|
||||||
|
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
*~
|
||||||
|
istored
|
||||||
|
istored.service
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# $Id$
|
||||||
|
#
|
||||||
|
# PROVIDE: mbased
|
||||||
|
# REQUIRE: DAEMON
|
||||||
|
|
||||||
|
. /etc/rc.subr
|
||||||
|
|
||||||
|
name="mbased"
|
||||||
|
rcvar="mbased_enable"
|
||||||
|
|
||||||
|
pidfile="@srv_rundir@/mbased.pid"
|
||||||
|
command="@prefix@/sbin/${name}"
|
||||||
|
command_args="--asDaemon=true"
|
||||||
|
procname="@prefix@/sbin/${name}"
|
||||||
|
|
||||||
|
load_rc_config ${name}
|
||||||
|
|
||||||
|
: ${mbased_enable:="NO"}
|
||||||
|
|
||||||
|
run_rc_command "$1"
|
||||||
|
#EOF
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user