mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Desktop integration (#2073)
* Open stash in system tray on Windows/MacOS * Add desktop notifications * MacOS Bundling * Add binary icon Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
e48b2ba3e8
commit
0e514183a7
1
vendor/github.com/apenwarr/fixconsole/.gitignore
generated
vendored
Normal file
1
vendor/github.com/apenwarr/fixconsole/.gitignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*~
|
||||
202
vendor/github.com/apenwarr/fixconsole/LICENSE
generated
vendored
Normal file
202
vendor/github.com/apenwarr/fixconsole/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
14
vendor/github.com/apenwarr/fixconsole/fixconsole_default.go
generated
vendored
Normal file
14
vendor/github.com/apenwarr/fixconsole/fixconsole_default.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// +build !windows
|
||||
|
||||
package fixconsole
|
||||
|
||||
// On non-windows platforms, we don't need to do anything. The console
|
||||
// starts off attached already, if it exists.
|
||||
|
||||
func AttachConsole() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func FixConsoleIfNeeded() error {
|
||||
return nil
|
||||
}
|
||||
132
vendor/github.com/apenwarr/fixconsole/fixconsole_windows.go
generated
vendored
Normal file
132
vendor/github.com/apenwarr/fixconsole/fixconsole_windows.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
package fixconsole
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/apenwarr/w32"
|
||||
"golang.org/x/sys/windows"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func AttachConsole() error {
|
||||
const ATTACH_PARENT_PROCESS = ^uintptr(0)
|
||||
proc := syscall.MustLoadDLL("kernel32.dll").MustFindProc("AttachConsole")
|
||||
r1, _, err := proc.Call(ATTACH_PARENT_PROCESS)
|
||||
if r1 == 0 {
|
||||
errno, ok := err.(syscall.Errno)
|
||||
if ok && errno == w32.ERROR_INVALID_HANDLE {
|
||||
// console handle doesn't exist; not a real
|
||||
// error, but the console handle will be
|
||||
// invalid.
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var oldStdin, oldStdout, oldStderr *os.File
|
||||
|
||||
// Windows console output is a mess.
|
||||
//
|
||||
// If you compile as "-H windows", then if you launch your program without
|
||||
// a console, Windows forcibly creates one to use as your stdin/stdout, which
|
||||
// is silly for a GUI app, so we can't do that.
|
||||
//
|
||||
// If you compile as "-H windowsgui", then it doesn't create a console for
|
||||
// your app... but also doesn't provide a working stdin/stdout/stderr even if
|
||||
// you *did* launch from the console. However, you can use AttachConsole()
|
||||
// to get a handle to your parent process's console, if any, and then
|
||||
// os.NewFile() to turn that handle into a fd usable as stdout/stderr.
|
||||
//
|
||||
// However, then you have the problem that if you redirect stdout or stderr
|
||||
// from the shell, you end up ignoring the redirection by forcing it to the
|
||||
// console.
|
||||
//
|
||||
// To fix *that*, we have to detect whether there was a pre-existing stdout
|
||||
// or not. We can check GetStdHandle(), which returns 0 for "should be
|
||||
// console" and nonzero for "already pointing at a file."
|
||||
//
|
||||
// Be careful though! As soon as you run AttachConsole(), it resets *all*
|
||||
// the GetStdHandle() handles to point them at the console instead, thus
|
||||
// throwing away the original file redirects. So we have to GetStdHandle()
|
||||
// *before* AttachConsole().
|
||||
//
|
||||
// For some reason, powershell redirections provide a valid file handle, but
|
||||
// writing to that handle doesn't write to the file. I haven't found a way
|
||||
// to work around that. (Windows 10.0.17763.379)
|
||||
//
|
||||
// Net result is as follows.
|
||||
// Before:
|
||||
// SHELL NON-REDIRECTED REDIRECTED
|
||||
// explorer.exe no console n/a
|
||||
// cmd.exe broken works
|
||||
// powershell broken broken
|
||||
// WSL bash broken works
|
||||
// After
|
||||
// SHELL NON-REDIRECTED REDIRECTED
|
||||
// explorer.exe no console n/a
|
||||
// cmd.exe works works
|
||||
// powershell works broken
|
||||
// WSL bash works works
|
||||
//
|
||||
// We don't seem to make anything worse, at least.
|
||||
func FixConsoleIfNeeded() error {
|
||||
// Retain the original console objects, to prevent Go from automatically
|
||||
// closing their file descriptors when they get garbage collected.
|
||||
// You never want to close file descriptors 0, 1, and 2.
|
||||
oldStdin, oldStdout, oldStderr = os.Stdin, os.Stdout, os.Stderr
|
||||
|
||||
stdin, _ := syscall.GetStdHandle(syscall.STD_INPUT_HANDLE)
|
||||
stdout, _ := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE)
|
||||
stderr, _ := syscall.GetStdHandle(syscall.STD_ERROR_HANDLE)
|
||||
|
||||
var invalid syscall.Handle
|
||||
con := invalid
|
||||
|
||||
if stdin == invalid || stdout == invalid || stderr == invalid {
|
||||
err := AttachConsole()
|
||||
if err != nil {
|
||||
return fmt.Errorf("attachconsole: %v", err)
|
||||
}
|
||||
|
||||
if stdin == invalid {
|
||||
stdin, _ = syscall.GetStdHandle(syscall.STD_INPUT_HANDLE)
|
||||
}
|
||||
if stdout == invalid {
|
||||
stdout, _ = syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE)
|
||||
con = stdout
|
||||
}
|
||||
if stderr == invalid {
|
||||
stderr, _ = syscall.GetStdHandle(syscall.STD_ERROR_HANDLE)
|
||||
con = stderr
|
||||
}
|
||||
}
|
||||
|
||||
if con != invalid {
|
||||
// Make sure the console is configured to convert
|
||||
// \n to \r\n, like Go programs expect.
|
||||
h := windows.Handle(con)
|
||||
var st uint32
|
||||
err := windows.GetConsoleMode(h, &st)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetConsoleMode: %v", err)
|
||||
}
|
||||
err = windows.SetConsoleMode(h, st&^windows.DISABLE_NEWLINE_AUTO_RETURN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("SetConsoleMode: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if stdin != invalid {
|
||||
os.Stdin = os.NewFile(uintptr(stdin), "stdin")
|
||||
}
|
||||
if stdout != invalid {
|
||||
os.Stdout = os.NewFile(uintptr(stdout), "stdout")
|
||||
}
|
||||
if stderr != invalid {
|
||||
os.Stderr = os.NewFile(uintptr(stderr), "stderr")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
19
vendor/github.com/apenwarr/w32/AUTHORS
generated
vendored
Normal file
19
vendor/github.com/apenwarr/w32/AUTHORS
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# This is the official list of 'w32' authors for copyright purposes.
|
||||
|
||||
# Names should be added to this file as
|
||||
# Name or Organization <email address>
|
||||
# The email address is not required for organizations.
|
||||
|
||||
# Please keep the list sorted.
|
||||
|
||||
# Contributors
|
||||
# ============
|
||||
|
||||
Allen Dang <allengnr@gmail.com>
|
||||
Benny Siegert <bsiegert@gmail.com>
|
||||
Bruno Bigras <bigras.bruno@gmail.com>
|
||||
Daniel Joos
|
||||
Gerald Rosenberg <gerald.rosenberg@gmail.com>
|
||||
Liam Bowen <liambowen@gmail.com>
|
||||
Michael Henke
|
||||
Paul Maddox <paul.maddox@gmail.com>
|
||||
23
vendor/github.com/apenwarr/w32/LICENSE
generated
vendored
Normal file
23
vendor/github.com/apenwarr/w32/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
Copyright (c) 2010-2012 The w32 Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. The names of the authors may not be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
33
vendor/github.com/apenwarr/w32/README.md
generated
vendored
Normal file
33
vendor/github.com/apenwarr/w32/README.md
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
About w32
|
||||
==========
|
||||
|
||||
w32 is a wrapper of windows apis for the Go Programming Language.
|
||||
|
||||
It wraps win32 apis to "Go style" to make them easier to use.
|
||||
|
||||
Setup
|
||||
=====
|
||||
|
||||
1. Make sure you have a working Go installation and build environment,
|
||||
see this go-nuts post for details:
|
||||
http://groups.google.com/group/golang-nuts/msg/5c87630a84f4fd0c
|
||||
|
||||
Updated versions of the Windows Go build are available here:
|
||||
http://code.google.com/p/gomingw/downloads/list
|
||||
|
||||
2. Create a "gopath" directory if you do not have one yet and set the
|
||||
GOPATH variable accordingly. For example:
|
||||
mkdir -p go-externals/src
|
||||
export GOPATH=${PWD}/go-externals
|
||||
|
||||
3. go get github.com/AllenDang/w32
|
||||
|
||||
4. go install github.com/AllenDang/w32...
|
||||
|
||||
Contribute
|
||||
==========
|
||||
|
||||
Contributions in form of design, code, documentation, bug reporting or other
|
||||
ways you see fit are very welcome.
|
||||
|
||||
Thank You!
|
||||
389
vendor/github.com/apenwarr/w32/advapi32.go
generated
vendored
Normal file
389
vendor/github.com/apenwarr/w32/advapi32.go
generated
vendored
Normal file
@@ -0,0 +1,389 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
|
||||
|
||||
// procRegSetKeyValue = modadvapi32.NewProc("RegSetKeyValueW")
|
||||
procCloseEventLog = modadvapi32.NewProc("CloseEventLog")
|
||||
procCloseServiceHandle = modadvapi32.NewProc("CloseServiceHandle")
|
||||
procControlService = modadvapi32.NewProc("ControlService")
|
||||
procControlTrace = modadvapi32.NewProc("ControlTraceW")
|
||||
procInitializeSecurityDescriptor = modadvapi32.NewProc("InitializeSecurityDescriptor")
|
||||
procOpenEventLog = modadvapi32.NewProc("OpenEventLogW")
|
||||
procOpenSCManager = modadvapi32.NewProc("OpenSCManagerW")
|
||||
procOpenService = modadvapi32.NewProc("OpenServiceW")
|
||||
procReadEventLog = modadvapi32.NewProc("ReadEventLogW")
|
||||
procRegCloseKey = modadvapi32.NewProc("RegCloseKey")
|
||||
procRegCreateKeyEx = modadvapi32.NewProc("RegCreateKeyExW")
|
||||
procRegEnumKeyEx = modadvapi32.NewProc("RegEnumKeyExW")
|
||||
procRegGetValue = modadvapi32.NewProc("RegGetValueW")
|
||||
procRegOpenKeyEx = modadvapi32.NewProc("RegOpenKeyExW")
|
||||
procRegSetValueEx = modadvapi32.NewProc("RegSetValueExW")
|
||||
procSetSecurityDescriptorDacl = modadvapi32.NewProc("SetSecurityDescriptorDacl")
|
||||
procStartService = modadvapi32.NewProc("StartServiceW")
|
||||
procStartTrace = modadvapi32.NewProc("StartTraceW")
|
||||
)
|
||||
|
||||
var (
|
||||
SystemTraceControlGuid = GUID{
|
||||
0x9e814aad,
|
||||
0x3204,
|
||||
0x11d2,
|
||||
[8]byte{0x9a, 0x82, 0x00, 0x60, 0x08, 0xa8, 0x69, 0x39},
|
||||
}
|
||||
)
|
||||
|
||||
func RegCreateKey(hKey HKEY, subKey string) HKEY {
|
||||
var result HKEY
|
||||
ret, _, _ := procRegCreateKeyEx.Call(
|
||||
uintptr(hKey),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
|
||||
uintptr(0),
|
||||
uintptr(0),
|
||||
uintptr(0),
|
||||
uintptr(KEY_ALL_ACCESS),
|
||||
uintptr(0),
|
||||
uintptr(unsafe.Pointer(&result)),
|
||||
uintptr(0))
|
||||
_ = ret
|
||||
return result
|
||||
}
|
||||
|
||||
func RegOpenKeyEx(hKey HKEY, subKey string, samDesired uint32) HKEY {
|
||||
var result HKEY
|
||||
ret, _, _ := procRegOpenKeyEx.Call(
|
||||
uintptr(hKey),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
|
||||
uintptr(0),
|
||||
uintptr(samDesired),
|
||||
uintptr(unsafe.Pointer(&result)))
|
||||
|
||||
if ret != ERROR_SUCCESS {
|
||||
panic(fmt.Sprintf("RegOpenKeyEx(%d, %s, %d) failed", hKey, subKey, samDesired))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func RegCloseKey(hKey HKEY) error {
|
||||
var err error
|
||||
ret, _, _ := procRegCloseKey.Call(
|
||||
uintptr(hKey))
|
||||
|
||||
if ret != ERROR_SUCCESS {
|
||||
err = errors.New("RegCloseKey failed")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func RegGetRaw(hKey HKEY, subKey string, value string) []byte {
|
||||
var bufLen uint32
|
||||
var valptr unsafe.Pointer
|
||||
if len(value) > 0 {
|
||||
valptr = unsafe.Pointer(syscall.StringToUTF16Ptr(value))
|
||||
}
|
||||
procRegGetValue.Call(
|
||||
uintptr(hKey),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
|
||||
uintptr(valptr),
|
||||
uintptr(RRF_RT_ANY),
|
||||
0,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&bufLen)))
|
||||
|
||||
if bufLen == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
buf := make([]byte, bufLen)
|
||||
ret, _, _ := procRegGetValue.Call(
|
||||
uintptr(hKey),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
|
||||
uintptr(valptr),
|
||||
uintptr(RRF_RT_ANY),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uintptr(unsafe.Pointer(&bufLen)))
|
||||
|
||||
if ret != ERROR_SUCCESS {
|
||||
return nil
|
||||
}
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
func RegSetBinary(hKey HKEY, subKey string, value []byte) (errno int) {
|
||||
var lptr, vptr unsafe.Pointer
|
||||
if len(subKey) > 0 {
|
||||
lptr = unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))
|
||||
}
|
||||
if len(value) > 0 {
|
||||
vptr = unsafe.Pointer(&value[0])
|
||||
}
|
||||
ret, _, _ := procRegSetValueEx.Call(
|
||||
uintptr(hKey),
|
||||
uintptr(lptr),
|
||||
uintptr(0),
|
||||
uintptr(REG_BINARY),
|
||||
uintptr(vptr),
|
||||
uintptr(len(value)))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func RegGetString(hKey HKEY, subKey string, value string) string {
|
||||
var bufLen uint32
|
||||
procRegGetValue.Call(
|
||||
uintptr(hKey),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(value))),
|
||||
uintptr(RRF_RT_REG_SZ),
|
||||
0,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&bufLen)))
|
||||
|
||||
if bufLen == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
buf := make([]uint16, bufLen)
|
||||
ret, _, _ := procRegGetValue.Call(
|
||||
uintptr(hKey),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(value))),
|
||||
uintptr(RRF_RT_REG_SZ),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uintptr(unsafe.Pointer(&bufLen)))
|
||||
|
||||
if ret != ERROR_SUCCESS {
|
||||
return ""
|
||||
}
|
||||
|
||||
return syscall.UTF16ToString(buf)
|
||||
}
|
||||
|
||||
/*
|
||||
func RegSetKeyValue(hKey HKEY, subKey string, valueName string, dwType uint32, data uintptr, cbData uint16) (errno int) {
|
||||
ret, _, _ := procRegSetKeyValue.Call(
|
||||
uintptr(hKey),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(subKey))),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(valueName))),
|
||||
uintptr(dwType),
|
||||
data,
|
||||
uintptr(cbData))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
*/
|
||||
|
||||
func RegEnumKeyEx(hKey HKEY, index uint32) string {
|
||||
var bufLen uint32 = 255
|
||||
buf := make([]uint16, bufLen)
|
||||
procRegEnumKeyEx.Call(
|
||||
uintptr(hKey),
|
||||
uintptr(index),
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uintptr(unsafe.Pointer(&bufLen)),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0)
|
||||
return syscall.UTF16ToString(buf)
|
||||
}
|
||||
|
||||
func OpenEventLog(servername string, sourcename string) HANDLE {
|
||||
ret, _, _ := procOpenEventLog.Call(
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(servername))),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(sourcename))))
|
||||
|
||||
return HANDLE(ret)
|
||||
}
|
||||
|
||||
func ReadEventLog(eventlog HANDLE, readflags, recordoffset uint32, buffer []byte, numberofbytestoread uint32, bytesread, minnumberofbytesneeded *uint32) bool {
|
||||
ret, _, _ := procReadEventLog.Call(
|
||||
uintptr(eventlog),
|
||||
uintptr(readflags),
|
||||
uintptr(recordoffset),
|
||||
uintptr(unsafe.Pointer(&buffer[0])),
|
||||
uintptr(numberofbytestoread),
|
||||
uintptr(unsafe.Pointer(bytesread)),
|
||||
uintptr(unsafe.Pointer(minnumberofbytesneeded)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func CloseEventLog(eventlog HANDLE) bool {
|
||||
ret, _, _ := procCloseEventLog.Call(
|
||||
uintptr(eventlog))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func OpenSCManager(lpMachineName, lpDatabaseName string, dwDesiredAccess uint32) (HANDLE, error) {
|
||||
var p1, p2 uintptr
|
||||
if len(lpMachineName) > 0 {
|
||||
p1 = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpMachineName)))
|
||||
}
|
||||
if len(lpDatabaseName) > 0 {
|
||||
p2 = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDatabaseName)))
|
||||
}
|
||||
ret, _, _ := procOpenSCManager.Call(
|
||||
p1,
|
||||
p2,
|
||||
uintptr(dwDesiredAccess))
|
||||
|
||||
if ret == 0 {
|
||||
return 0, syscall.GetLastError()
|
||||
}
|
||||
|
||||
return HANDLE(ret), nil
|
||||
}
|
||||
|
||||
func CloseServiceHandle(hSCObject HANDLE) error {
|
||||
ret, _, _ := procCloseServiceHandle.Call(uintptr(hSCObject))
|
||||
if ret == 0 {
|
||||
return syscall.GetLastError()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func OpenService(hSCManager HANDLE, lpServiceName string, dwDesiredAccess uint32) (HANDLE, error) {
|
||||
ret, _, _ := procOpenService.Call(
|
||||
uintptr(hSCManager),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpServiceName))),
|
||||
uintptr(dwDesiredAccess))
|
||||
|
||||
if ret == 0 {
|
||||
return 0, syscall.GetLastError()
|
||||
}
|
||||
|
||||
return HANDLE(ret), nil
|
||||
}
|
||||
|
||||
func StartService(hService HANDLE, lpServiceArgVectors []string) error {
|
||||
l := len(lpServiceArgVectors)
|
||||
var ret uintptr
|
||||
if l == 0 {
|
||||
ret, _, _ = procStartService.Call(
|
||||
uintptr(hService),
|
||||
0,
|
||||
0)
|
||||
} else {
|
||||
lpArgs := make([]uintptr, l)
|
||||
for i := 0; i < l; i++ {
|
||||
lpArgs[i] = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpServiceArgVectors[i])))
|
||||
}
|
||||
|
||||
ret, _, _ = procStartService.Call(
|
||||
uintptr(hService),
|
||||
uintptr(l),
|
||||
uintptr(unsafe.Pointer(&lpArgs[0])))
|
||||
}
|
||||
|
||||
if ret == 0 {
|
||||
return syscall.GetLastError()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ControlService(hService HANDLE, dwControl uint32, lpServiceStatus *SERVICE_STATUS) bool {
|
||||
if lpServiceStatus == nil {
|
||||
panic("ControlService:lpServiceStatus cannot be nil")
|
||||
}
|
||||
|
||||
ret, _, _ := procControlService.Call(
|
||||
uintptr(hService),
|
||||
uintptr(dwControl),
|
||||
uintptr(unsafe.Pointer(lpServiceStatus)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func ControlTrace(hTrace TRACEHANDLE, lpSessionName string, props *EVENT_TRACE_PROPERTIES, dwControl uint32) (success bool, e error) {
|
||||
|
||||
ret, _, _ := procControlTrace.Call(
|
||||
uintptr(unsafe.Pointer(hTrace)),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpSessionName))),
|
||||
uintptr(unsafe.Pointer(props)),
|
||||
uintptr(dwControl))
|
||||
|
||||
if ret == ERROR_SUCCESS {
|
||||
return true, nil
|
||||
}
|
||||
e = errors.New(fmt.Sprintf("error: 0x%x", ret))
|
||||
return
|
||||
}
|
||||
|
||||
func StartTrace(lpSessionName string, props *EVENT_TRACE_PROPERTIES) (hTrace TRACEHANDLE, e error) {
|
||||
|
||||
ret, _, _ := procStartTrace.Call(
|
||||
uintptr(unsafe.Pointer(&hTrace)),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpSessionName))),
|
||||
uintptr(unsafe.Pointer(props)))
|
||||
|
||||
if ret == ERROR_SUCCESS {
|
||||
return
|
||||
}
|
||||
e = errors.New(fmt.Sprintf("error: 0x%x", ret))
|
||||
return
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa378863(v=vs.85).aspx
|
||||
func InitializeSecurityDescriptor(rev uint16) (pSecurityDescriptor *SECURITY_DESCRIPTOR, e error) {
|
||||
|
||||
pSecurityDescriptor = &SECURITY_DESCRIPTOR{}
|
||||
|
||||
ret, _, _ := procInitializeSecurityDescriptor.Call(
|
||||
uintptr(unsafe.Pointer(pSecurityDescriptor)),
|
||||
uintptr(rev),
|
||||
)
|
||||
|
||||
if ret != 0 {
|
||||
return
|
||||
}
|
||||
e = syscall.GetLastError()
|
||||
return
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa379583(v=vs.85).aspx
|
||||
func SetSecurityDescriptorDacl(pSecurityDescriptor *SECURITY_DESCRIPTOR, pDacl *ACL) (e error) {
|
||||
|
||||
if pSecurityDescriptor == nil {
|
||||
return errors.New("null descriptor")
|
||||
}
|
||||
|
||||
var ret uintptr
|
||||
if pDacl == nil {
|
||||
ret, _, _ = procSetSecurityDescriptorDacl.Call(
|
||||
uintptr(unsafe.Pointer(pSecurityDescriptor)),
|
||||
uintptr(1), // DaclPresent
|
||||
uintptr(0), // pDacl
|
||||
uintptr(0), // DaclDefaulted
|
||||
)
|
||||
} else {
|
||||
ret, _, _ = procSetSecurityDescriptorDacl.Call(
|
||||
uintptr(unsafe.Pointer(pSecurityDescriptor)),
|
||||
uintptr(1), // DaclPresent
|
||||
uintptr(unsafe.Pointer(pDacl)),
|
||||
uintptr(0), //DaclDefaulted
|
||||
)
|
||||
}
|
||||
|
||||
if ret != 0 {
|
||||
return
|
||||
}
|
||||
e = syscall.GetLastError()
|
||||
return
|
||||
}
|
||||
300
vendor/github.com/apenwarr/w32/advapi32_constants.go
generated
vendored
Normal file
300
vendor/github.com/apenwarr/w32/advapi32_constants.go
generated
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
package w32
|
||||
|
||||
// Registry predefined keys
|
||||
const (
|
||||
HKEY_CLASSES_ROOT HKEY = 0x80000000
|
||||
HKEY_CURRENT_USER HKEY = 0x80000001
|
||||
HKEY_LOCAL_MACHINE HKEY = 0x80000002
|
||||
HKEY_USERS HKEY = 0x80000003
|
||||
HKEY_PERFORMANCE_DATA HKEY = 0x80000004
|
||||
HKEY_CURRENT_CONFIG HKEY = 0x80000005
|
||||
HKEY_DYN_DATA HKEY = 0x80000006
|
||||
)
|
||||
|
||||
// Registry Key Security and Access Rights
|
||||
const (
|
||||
KEY_ALL_ACCESS = 0xF003F
|
||||
KEY_CREATE_SUB_KEY = 0x0004
|
||||
KEY_ENUMERATE_SUB_KEYS = 0x0008
|
||||
KEY_NOTIFY = 0x0010
|
||||
KEY_QUERY_VALUE = 0x0001
|
||||
KEY_SET_VALUE = 0x0002
|
||||
KEY_READ = 0x20019
|
||||
KEY_WRITE = 0x20006
|
||||
)
|
||||
|
||||
const (
|
||||
NFR_ANSI = 1
|
||||
NFR_UNICODE = 2
|
||||
NF_QUERY = 3
|
||||
NF_REQUERY = 4
|
||||
)
|
||||
|
||||
// Registry value types
|
||||
const (
|
||||
RRF_RT_REG_NONE = 0x00000001
|
||||
RRF_RT_REG_SZ = 0x00000002
|
||||
RRF_RT_REG_EXPAND_SZ = 0x00000004
|
||||
RRF_RT_REG_BINARY = 0x00000008
|
||||
RRF_RT_REG_DWORD = 0x00000010
|
||||
RRF_RT_REG_MULTI_SZ = 0x00000020
|
||||
RRF_RT_REG_QWORD = 0x00000040
|
||||
RRF_RT_DWORD = (RRF_RT_REG_BINARY | RRF_RT_REG_DWORD)
|
||||
RRF_RT_QWORD = (RRF_RT_REG_BINARY | RRF_RT_REG_QWORD)
|
||||
RRF_RT_ANY = 0x0000ffff
|
||||
RRF_NOEXPAND = 0x10000000
|
||||
RRF_ZEROONFAILURE = 0x20000000
|
||||
REG_PROCESS_APPKEY = 0x00000001
|
||||
REG_MUI_STRING_TRUNCATE = 0x00000001
|
||||
)
|
||||
|
||||
// Service Control Manager object specific access types
|
||||
const (
|
||||
SC_MANAGER_CONNECT = 0x0001
|
||||
SC_MANAGER_CREATE_SERVICE = 0x0002
|
||||
SC_MANAGER_ENUMERATE_SERVICE = 0x0004
|
||||
SC_MANAGER_LOCK = 0x0008
|
||||
SC_MANAGER_QUERY_LOCK_STATUS = 0x0010
|
||||
SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020
|
||||
SC_MANAGER_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG
|
||||
)
|
||||
|
||||
// Service Types (Bit Mask)
|
||||
const (
|
||||
SERVICE_KERNEL_DRIVER = 0x00000001
|
||||
SERVICE_FILE_SYSTEM_DRIVER = 0x00000002
|
||||
SERVICE_ADAPTER = 0x00000004
|
||||
SERVICE_RECOGNIZER_DRIVER = 0x00000008
|
||||
SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER
|
||||
SERVICE_WIN32_OWN_PROCESS = 0x00000010
|
||||
SERVICE_WIN32_SHARE_PROCESS = 0x00000020
|
||||
SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS
|
||||
SERVICE_INTERACTIVE_PROCESS = 0x00000100
|
||||
SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS
|
||||
)
|
||||
|
||||
// Service State -- for CurrentState
|
||||
const (
|
||||
SERVICE_STOPPED = 0x00000001
|
||||
SERVICE_START_PENDING = 0x00000002
|
||||
SERVICE_STOP_PENDING = 0x00000003
|
||||
SERVICE_RUNNING = 0x00000004
|
||||
SERVICE_CONTINUE_PENDING = 0x00000005
|
||||
SERVICE_PAUSE_PENDING = 0x00000006
|
||||
SERVICE_PAUSED = 0x00000007
|
||||
)
|
||||
|
||||
// Controls Accepted (Bit Mask)
|
||||
const (
|
||||
SERVICE_ACCEPT_STOP = 0x00000001
|
||||
SERVICE_ACCEPT_PAUSE_CONTINUE = 0x00000002
|
||||
SERVICE_ACCEPT_SHUTDOWN = 0x00000004
|
||||
SERVICE_ACCEPT_PARAMCHANGE = 0x00000008
|
||||
SERVICE_ACCEPT_NETBINDCHANGE = 0x00000010
|
||||
SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 0x00000020
|
||||
SERVICE_ACCEPT_POWEREVENT = 0x00000040
|
||||
SERVICE_ACCEPT_SESSIONCHANGE = 0x00000080
|
||||
SERVICE_ACCEPT_PRESHUTDOWN = 0x00000100
|
||||
SERVICE_ACCEPT_TIMECHANGE = 0x00000200
|
||||
SERVICE_ACCEPT_TRIGGEREVENT = 0x00000400
|
||||
)
|
||||
|
||||
// Service object specific access type
|
||||
const (
|
||||
SERVICE_QUERY_CONFIG = 0x0001
|
||||
SERVICE_CHANGE_CONFIG = 0x0002
|
||||
SERVICE_QUERY_STATUS = 0x0004
|
||||
SERVICE_ENUMERATE_DEPENDENTS = 0x0008
|
||||
SERVICE_START = 0x0010
|
||||
SERVICE_STOP = 0x0020
|
||||
SERVICE_PAUSE_CONTINUE = 0x0040
|
||||
SERVICE_INTERROGATE = 0x0080
|
||||
SERVICE_USER_DEFINED_CONTROL = 0x0100
|
||||
|
||||
SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
|
||||
SERVICE_QUERY_CONFIG |
|
||||
SERVICE_CHANGE_CONFIG |
|
||||
SERVICE_QUERY_STATUS |
|
||||
SERVICE_ENUMERATE_DEPENDENTS |
|
||||
SERVICE_START |
|
||||
SERVICE_STOP |
|
||||
SERVICE_PAUSE_CONTINUE |
|
||||
SERVICE_INTERROGATE |
|
||||
SERVICE_USER_DEFINED_CONTROL
|
||||
)
|
||||
|
||||
const (
|
||||
KERNEL_LOGGER_NAME = "NT Kernel Logger"
|
||||
)
|
||||
|
||||
// WNODE flags, for ETW (Event Tracing for Windows) / WMI
|
||||
const (
|
||||
WNODE_FLAG_ALL_DATA = 0x00000001
|
||||
WNODE_FLAG_SINGLE_INSTANCE = 0x00000002
|
||||
WNODE_FLAG_SINGLE_ITEM = 0x00000004
|
||||
WNODE_FLAG_EVENT_ITEM = 0x00000008
|
||||
WNODE_FLAG_FIXED_INSTANCE_SIZE = 0x00000010
|
||||
WNODE_FLAG_TOO_SMALL = 0x00000020
|
||||
WNODE_FLAG_INSTANCES_SAME = 0x00000040
|
||||
WNODE_FLAG_STATIC_INSTANCE_NAMES = 0x00000080
|
||||
WNODE_FLAG_INTERNAL = 0x00000100
|
||||
WNODE_FLAG_USE_TIMESTAMP = 0x00000200
|
||||
WNODE_FLAG_PERSIST_EVENT = 0x00000400
|
||||
WNODE_FLAG_EVENT_REFERENCE = 0x00002000
|
||||
WNODE_FLAG_ANSI_INSTANCENAMES = 0x00004000
|
||||
WNODE_FLAG_METHOD_ITEM = 0x00008000
|
||||
WNODE_FLAG_PDO_INSTANCE_NAMES = 0x00010000
|
||||
WNODE_FLAG_TRACED_GUID = 0x00020000
|
||||
WNODE_FLAG_LOG_WNODE = 0x00040000
|
||||
WNODE_FLAG_USE_GUID_PTR = 0x00080000
|
||||
WNODE_FLAG_USE_MOF_PTR = 0x00100000
|
||||
WNODE_FLAG_NO_HEADER = 0x00200000
|
||||
WNODE_FLAG_SEVERITY_MASK = 0xff000000
|
||||
)
|
||||
|
||||
// ETW flags and types etc
|
||||
const (
|
||||
EVENT_TRACE_TYPE_INFO = 0x00
|
||||
EVENT_TRACE_TYPE_START = 0x01
|
||||
EVENT_TRACE_TYPE_END = 0x02
|
||||
EVENT_TRACE_TYPE_STOP = 0x02
|
||||
EVENT_TRACE_TYPE_DC_START = 0x03
|
||||
EVENT_TRACE_TYPE_DC_END = 0x04
|
||||
EVENT_TRACE_TYPE_EXTENSION = 0x05
|
||||
EVENT_TRACE_TYPE_REPLY = 0x06
|
||||
EVENT_TRACE_TYPE_DEQUEUE = 0x07
|
||||
EVENT_TRACE_TYPE_RESUME = 0x07
|
||||
EVENT_TRACE_TYPE_CHECKPOINT = 0x08
|
||||
EVENT_TRACE_TYPE_SUSPEND = 0x08
|
||||
EVENT_TRACE_TYPE_WINEVT_SEND = 0x09
|
||||
EVENT_TRACE_TYPE_WINEVT_RECEIVE = 0XF0
|
||||
TRACE_LEVEL_NONE = 0
|
||||
TRACE_LEVEL_CRITICAL = 1
|
||||
TRACE_LEVEL_FATAL = 1
|
||||
TRACE_LEVEL_ERROR = 2
|
||||
TRACE_LEVEL_WARNING = 3
|
||||
TRACE_LEVEL_INFORMATION = 4
|
||||
TRACE_LEVEL_VERBOSE = 5
|
||||
TRACE_LEVEL_RESERVED6 = 6
|
||||
TRACE_LEVEL_RESERVED7 = 7
|
||||
TRACE_LEVEL_RESERVED8 = 8
|
||||
TRACE_LEVEL_RESERVED9 = 9
|
||||
EVENT_TRACE_TYPE_LOAD = 0x0A
|
||||
EVENT_TRACE_TYPE_IO_READ = 0x0A
|
||||
EVENT_TRACE_TYPE_IO_WRITE = 0x0B
|
||||
EVENT_TRACE_TYPE_IO_READ_INIT = 0x0C
|
||||
EVENT_TRACE_TYPE_IO_WRITE_INIT = 0x0D
|
||||
EVENT_TRACE_TYPE_IO_FLUSH = 0x0E
|
||||
EVENT_TRACE_TYPE_IO_FLUSH_INIT = 0x0F
|
||||
EVENT_TRACE_TYPE_MM_TF = 0x0A
|
||||
EVENT_TRACE_TYPE_MM_DZF = 0x0B
|
||||
EVENT_TRACE_TYPE_MM_COW = 0x0C
|
||||
EVENT_TRACE_TYPE_MM_GPF = 0x0D
|
||||
EVENT_TRACE_TYPE_MM_HPF = 0x0E
|
||||
EVENT_TRACE_TYPE_MM_AV = 0x0F
|
||||
EVENT_TRACE_TYPE_SEND = 0x0A
|
||||
EVENT_TRACE_TYPE_RECEIVE = 0x0B
|
||||
EVENT_TRACE_TYPE_CONNECT = 0x0C
|
||||
EVENT_TRACE_TYPE_DISCONNECT = 0x0D
|
||||
EVENT_TRACE_TYPE_RETRANSMIT = 0x0E
|
||||
EVENT_TRACE_TYPE_ACCEPT = 0x0F
|
||||
EVENT_TRACE_TYPE_RECONNECT = 0x10
|
||||
EVENT_TRACE_TYPE_CONNFAIL = 0x11
|
||||
EVENT_TRACE_TYPE_COPY_TCP = 0x12
|
||||
EVENT_TRACE_TYPE_COPY_ARP = 0x13
|
||||
EVENT_TRACE_TYPE_ACKFULL = 0x14
|
||||
EVENT_TRACE_TYPE_ACKPART = 0x15
|
||||
EVENT_TRACE_TYPE_ACKDUP = 0x16
|
||||
EVENT_TRACE_TYPE_GUIDMAP = 0x0A
|
||||
EVENT_TRACE_TYPE_CONFIG = 0x0B
|
||||
EVENT_TRACE_TYPE_SIDINFO = 0x0C
|
||||
EVENT_TRACE_TYPE_SECURITY = 0x0D
|
||||
EVENT_TRACE_TYPE_REGCREATE = 0x0A
|
||||
EVENT_TRACE_TYPE_REGOPEN = 0x0B
|
||||
EVENT_TRACE_TYPE_REGDELETE = 0x0C
|
||||
EVENT_TRACE_TYPE_REGQUERY = 0x0D
|
||||
EVENT_TRACE_TYPE_REGSETVALUE = 0x0E
|
||||
EVENT_TRACE_TYPE_REGDELETEVALUE = 0x0F
|
||||
EVENT_TRACE_TYPE_REGQUERYVALUE = 0x10
|
||||
EVENT_TRACE_TYPE_REGENUMERATEKEY = 0x11
|
||||
EVENT_TRACE_TYPE_REGENUMERATEVALUEKEY = 0x12
|
||||
EVENT_TRACE_TYPE_REGQUERYMULTIPLEVALUE = 0x13
|
||||
EVENT_TRACE_TYPE_REGSETINFORMATION = 0x14
|
||||
EVENT_TRACE_TYPE_REGFLUSH = 0x15
|
||||
EVENT_TRACE_TYPE_REGKCBCREATE = 0x16
|
||||
EVENT_TRACE_TYPE_REGKCBDELETE = 0x17
|
||||
EVENT_TRACE_TYPE_REGKCBRUNDOWNBEGIN = 0x18
|
||||
EVENT_TRACE_TYPE_REGKCBRUNDOWNEND = 0x19
|
||||
EVENT_TRACE_TYPE_REGVIRTUALIZE = 0x1A
|
||||
EVENT_TRACE_TYPE_REGCLOSE = 0x1B
|
||||
EVENT_TRACE_TYPE_REGSETSECURITY = 0x1C
|
||||
EVENT_TRACE_TYPE_REGQUERYSECURITY = 0x1D
|
||||
EVENT_TRACE_TYPE_REGCOMMIT = 0x1E
|
||||
EVENT_TRACE_TYPE_REGPREPARE = 0x1F
|
||||
EVENT_TRACE_TYPE_REGROLLBACK = 0x20
|
||||
EVENT_TRACE_TYPE_REGMOUNTHIVE = 0x21
|
||||
EVENT_TRACE_TYPE_CONFIG_CPU = 0x0A
|
||||
EVENT_TRACE_TYPE_CONFIG_PHYSICALDISK = 0x0B
|
||||
EVENT_TRACE_TYPE_CONFIG_LOGICALDISK = 0x0C
|
||||
EVENT_TRACE_TYPE_CONFIG_NIC = 0x0D
|
||||
EVENT_TRACE_TYPE_CONFIG_VIDEO = 0x0E
|
||||
EVENT_TRACE_TYPE_CONFIG_SERVICES = 0x0F
|
||||
EVENT_TRACE_TYPE_CONFIG_POWER = 0x10
|
||||
EVENT_TRACE_TYPE_CONFIG_NETINFO = 0x11
|
||||
EVENT_TRACE_TYPE_CONFIG_IRQ = 0x15
|
||||
EVENT_TRACE_TYPE_CONFIG_PNP = 0x16
|
||||
EVENT_TRACE_TYPE_CONFIG_IDECHANNEL = 0x17
|
||||
EVENT_TRACE_TYPE_CONFIG_PLATFORM = 0x19
|
||||
EVENT_TRACE_FLAG_PROCESS = 0x00000001
|
||||
EVENT_TRACE_FLAG_THREAD = 0x00000002
|
||||
EVENT_TRACE_FLAG_IMAGE_LOAD = 0x00000004
|
||||
EVENT_TRACE_FLAG_DISK_IO = 0x00000100
|
||||
EVENT_TRACE_FLAG_DISK_FILE_IO = 0x00000200
|
||||
EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS = 0x00001000
|
||||
EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS = 0x00002000
|
||||
EVENT_TRACE_FLAG_NETWORK_TCPIP = 0x00010000
|
||||
EVENT_TRACE_FLAG_REGISTRY = 0x00020000
|
||||
EVENT_TRACE_FLAG_DBGPRINT = 0x00040000
|
||||
EVENT_TRACE_FLAG_PROCESS_COUNTERS = 0x00000008
|
||||
EVENT_TRACE_FLAG_CSWITCH = 0x00000010
|
||||
EVENT_TRACE_FLAG_DPC = 0x00000020
|
||||
EVENT_TRACE_FLAG_INTERRUPT = 0x00000040
|
||||
EVENT_TRACE_FLAG_SYSTEMCALL = 0x00000080
|
||||
EVENT_TRACE_FLAG_DISK_IO_INIT = 0x00000400
|
||||
EVENT_TRACE_FLAG_ALPC = 0x00100000
|
||||
EVENT_TRACE_FLAG_SPLIT_IO = 0x00200000
|
||||
EVENT_TRACE_FLAG_DRIVER = 0x00800000
|
||||
EVENT_TRACE_FLAG_PROFILE = 0x01000000
|
||||
EVENT_TRACE_FLAG_FILE_IO = 0x02000000
|
||||
EVENT_TRACE_FLAG_FILE_IO_INIT = 0x04000000
|
||||
EVENT_TRACE_FLAG_DISPATCHER = 0x00000800
|
||||
EVENT_TRACE_FLAG_VIRTUAL_ALLOC = 0x00004000
|
||||
EVENT_TRACE_FLAG_EXTENSION = 0x80000000
|
||||
EVENT_TRACE_FLAG_FORWARD_WMI = 0x40000000
|
||||
EVENT_TRACE_FLAG_ENABLE_RESERVE = 0x20000000
|
||||
EVENT_TRACE_FILE_MODE_NONE = 0x00000000
|
||||
EVENT_TRACE_FILE_MODE_SEQUENTIAL = 0x00000001
|
||||
EVENT_TRACE_FILE_MODE_CIRCULAR = 0x00000002
|
||||
EVENT_TRACE_FILE_MODE_APPEND = 0x00000004
|
||||
EVENT_TRACE_REAL_TIME_MODE = 0x00000100
|
||||
EVENT_TRACE_DELAY_OPEN_FILE_MODE = 0x00000200
|
||||
EVENT_TRACE_BUFFERING_MODE = 0x00000400
|
||||
EVENT_TRACE_PRIVATE_LOGGER_MODE = 0x00000800
|
||||
EVENT_TRACE_ADD_HEADER_MODE = 0x00001000
|
||||
EVENT_TRACE_USE_GLOBAL_SEQUENCE = 0x00004000
|
||||
EVENT_TRACE_USE_LOCAL_SEQUENCE = 0x00008000
|
||||
EVENT_TRACE_RELOG_MODE = 0x00010000
|
||||
EVENT_TRACE_USE_PAGED_MEMORY = 0x01000000
|
||||
EVENT_TRACE_FILE_MODE_NEWFILE = 0x00000008
|
||||
EVENT_TRACE_FILE_MODE_PREALLOCATE = 0x00000020
|
||||
EVENT_TRACE_NONSTOPPABLE_MODE = 0x00000040
|
||||
EVENT_TRACE_SECURE_MODE = 0x00000080
|
||||
EVENT_TRACE_USE_KBYTES_FOR_SIZE = 0x00002000
|
||||
EVENT_TRACE_PRIVATE_IN_PROC = 0x00020000
|
||||
EVENT_TRACE_MODE_RESERVED = 0x00100000
|
||||
EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING = 0x10000000
|
||||
EVENT_TRACE_CONTROL_QUERY = 0
|
||||
EVENT_TRACE_CONTROL_STOP = 1
|
||||
EVENT_TRACE_CONTROL_UPDATE = 2
|
||||
EVENT_TRACE_CONTROL_FLUSH = 3
|
||||
)
|
||||
122
vendor/github.com/apenwarr/w32/advapi32_typedef.go
generated
vendored
Normal file
122
vendor/github.com/apenwarr/w32/advapi32_typedef.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
package w32
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa374931(v=vs.85).aspx
|
||||
type ACL struct {
|
||||
AclRevision byte
|
||||
Sbz1 byte
|
||||
AclSize uint16
|
||||
AceCount uint16
|
||||
Sbz2 uint16
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa379561(v=vs.85).aspx
|
||||
|
||||
type SECURITY_DESCRIPTOR_CONTROL uint16
|
||||
|
||||
type SECURITY_DESCRIPTOR struct {
|
||||
Revision byte
|
||||
Sbz1 byte
|
||||
Control SECURITY_DESCRIPTOR_CONTROL
|
||||
Owner uintptr
|
||||
Group uintptr
|
||||
Sacl *ACL
|
||||
Dacl *ACL
|
||||
}
|
||||
|
||||
type SID_IDENTIFIER_AUTHORITY struct {
|
||||
Value [6]byte
|
||||
}
|
||||
|
||||
// typedef struct _SID // 4 elements, 0xC bytes (sizeof)
|
||||
// {
|
||||
// /*0x000*/ UINT8 Revision;
|
||||
// /*0x001*/ UINT8 SubAuthorityCount;
|
||||
// /*0x002*/ struct _SID_IDENTIFIER_AUTHORITY IdentifierAuthority; // 1 elements, 0x6 bytes (sizeof)
|
||||
// /*0x008*/ ULONG32 SubAuthority[1];
|
||||
// }SID, *PSID;
|
||||
type SID struct {
|
||||
Revision byte
|
||||
SubAuthorityCount byte
|
||||
IdentifierAuthority SID_IDENTIFIER_AUTHORITY
|
||||
SubAuthority uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363646.aspx
|
||||
type EVENTLOGRECORD struct {
|
||||
Length uint32
|
||||
Reserved uint32
|
||||
RecordNumber uint32
|
||||
TimeGenerated uint32
|
||||
TimeWritten uint32
|
||||
EventID uint32
|
||||
EventType uint16
|
||||
NumStrings uint16
|
||||
EventCategory uint16
|
||||
ReservedFlags uint16
|
||||
ClosingRecordNumber uint32
|
||||
StringOffset uint32
|
||||
UserSidLength uint32
|
||||
UserSidOffset uint32
|
||||
DataLength uint32
|
||||
DataOffset uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685996.aspx
|
||||
type SERVICE_STATUS struct {
|
||||
DwServiceType uint32
|
||||
DwCurrentState uint32
|
||||
DwControlsAccepted uint32
|
||||
DwWin32ExitCode uint32
|
||||
DwServiceSpecificExitCode uint32
|
||||
DwCheckPoint uint32
|
||||
DwWaitHint uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa364160(v=vs.85).aspx
|
||||
type WNODE_HEADER struct {
|
||||
BufferSize uint32
|
||||
ProviderId uint32
|
||||
HistoricalContext uint64
|
||||
KernelHandle HANDLE
|
||||
Guid GUID
|
||||
ClientContext uint32
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
// These partially compensate for the anonymous unions we removed, but there
|
||||
// are no setters.
|
||||
func (w WNODE_HEADER) TimeStamp() uint64 {
|
||||
// TODO: Cast to the stupid LARGE_INTEGER struct which is, itself, nasty
|
||||
// and union-y
|
||||
return uint64(w.KernelHandle)
|
||||
}
|
||||
|
||||
func (w WNODE_HEADER) Version() uint32 {
|
||||
return uint32(w.HistoricalContext >> 32)
|
||||
}
|
||||
|
||||
func (w WNODE_HEADER) Linkage() uint32 {
|
||||
return uint32(w.HistoricalContext)
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363784(v=vs.85).aspx
|
||||
type EVENT_TRACE_PROPERTIES struct {
|
||||
Wnode WNODE_HEADER
|
||||
BufferSize uint32
|
||||
MinimumBuffers uint32
|
||||
MaximumBuffers uint32
|
||||
MaximumFileSize uint32
|
||||
LogFileMode uint32
|
||||
FlushTimer uint32
|
||||
EnableFlags uint32
|
||||
AgeLimit int32
|
||||
NumberOfBuffers uint32
|
||||
FreeBuffers uint32
|
||||
EventsLost uint32
|
||||
BuffersWritten uint32
|
||||
LogBuffersLost uint32
|
||||
RealTimeBuffersLost uint32
|
||||
LoggerThreadId HANDLE
|
||||
LogFileNameOffset uint32
|
||||
LoggerNameOffset uint32
|
||||
}
|
||||
304
vendor/github.com/apenwarr/w32/alpc.go
generated
vendored
Normal file
304
vendor/github.com/apenwarr/w32/alpc.go
generated
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
// "github.com/davecgh/go-spew/spew"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modntdll = syscall.NewLazyDLL("ntdll.dll")
|
||||
|
||||
procAlpcGetMessageAttribute = modntdll.NewProc("AlpcGetMessageAttribute")
|
||||
procNtAlpcAcceptConnectPort = modntdll.NewProc("NtAlpcAcceptConnectPort")
|
||||
procNtAlpcCancelMessage = modntdll.NewProc("NtAlpcCancelMessage")
|
||||
procNtAlpcConnectPort = modntdll.NewProc("NtAlpcConnectPort")
|
||||
procNtAlpcCreatePort = modntdll.NewProc("NtAlpcCreatePort")
|
||||
procNtAlpcDisconnectPort = modntdll.NewProc("NtAlpcDisconnectPort")
|
||||
procNtAlpcSendWaitReceivePort = modntdll.NewProc("NtAlpcSendWaitReceivePort")
|
||||
procRtlCreateUnicodeStringFromAsciiz = modntdll.NewProc("RtlCreateUnicodeStringFromAsciiz")
|
||||
)
|
||||
|
||||
//func RtlCreateUnicodeStringFromAsciiz(s string) (us UNICODE_STRING, e error) {
|
||||
//
|
||||
// cs := C.CString(s)
|
||||
// defer C.free(unsafe.Pointer(cs))
|
||||
//
|
||||
// ret, _, lastErr := procRtlCreateUnicodeStringFromAsciiz.Call(
|
||||
// uintptr(unsafe.Pointer(&us)),
|
||||
// uintptr(unsafe.Pointer(cs)),
|
||||
// )
|
||||
//
|
||||
// if ret != 1 { // ret is a BOOL ( I think )
|
||||
// e = lastErr
|
||||
// }
|
||||
//
|
||||
// return
|
||||
//}
|
||||
|
||||
//func newUnicodeString(s string) (us UNICODE_STRING, e error) {
|
||||
// // TODO probably not the most efficient way to do this, but I couldn't
|
||||
// // work out how to manually initialize the UNICODE_STRING struct in a way
|
||||
// // that the ALPC subsystem liked.
|
||||
// us, e = RtlCreateUnicodeStringFromAsciiz(s)
|
||||
// return
|
||||
//}
|
||||
|
||||
// (this is a macro)
|
||||
// VOID InitializeObjectAttributes(
|
||||
// [out] POBJECT_ATTRIBUTES InitializedAttributes,
|
||||
// [in] PUNICODE_STRING ObjectName,
|
||||
// [in] ULONG Attributes,
|
||||
// [in] HANDLE RootDirectory,
|
||||
// [in, optional] PSECURITY_DESCRIPTOR SecurityDescriptor
|
||||
// )
|
||||
//func InitializeObjectAttributes(
|
||||
// name string,
|
||||
// attributes uint32,
|
||||
// rootDir HANDLE,
|
||||
// pSecurityDescriptor *SECURITY_DESCRIPTOR,
|
||||
//) (oa OBJECT_ATTRIBUTES, e error) {
|
||||
//
|
||||
// oa = OBJECT_ATTRIBUTES{
|
||||
// RootDirectory: rootDir,
|
||||
// Attributes: attributes,
|
||||
// SecurityDescriptor: pSecurityDescriptor,
|
||||
// }
|
||||
// oa.Length = uint32(unsafe.Sizeof(oa))
|
||||
//
|
||||
// if len(name) > 0 {
|
||||
// us, err := newUnicodeString(name)
|
||||
// if err != nil {
|
||||
// e = err
|
||||
// return
|
||||
// }
|
||||
// oa.ObjectName = &us
|
||||
// }
|
||||
//
|
||||
// return
|
||||
//}
|
||||
|
||||
// NTSTATUS
|
||||
// NtAlpcCreatePort(
|
||||
// __out PHANDLE PortHandle,
|
||||
// __in POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
// __in_opt PALPC_PORT_ATTRIBUTES PortAttributes
|
||||
// );
|
||||
func NtAlpcCreatePort(pObjectAttributes *OBJECT_ATTRIBUTES, pPortAttributes *ALPC_PORT_ATTRIBUTES) (hPort HANDLE, e error) {
|
||||
|
||||
ret, _, _ := procNtAlpcCreatePort.Call(
|
||||
uintptr(unsafe.Pointer(&hPort)),
|
||||
uintptr(unsafe.Pointer(pObjectAttributes)),
|
||||
uintptr(unsafe.Pointer(pPortAttributes)),
|
||||
)
|
||||
|
||||
if ret != ERROR_SUCCESS {
|
||||
return hPort, fmt.Errorf("0x%x", ret)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NTSTATUS
|
||||
// NtAlpcConnectPort(
|
||||
// __out PHANDLE PortHandle,
|
||||
// __in PUNICODE_STRING PortName,
|
||||
// __in POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
// __in_opt PALPC_PORT_ATTRIBUTES PortAttributes,
|
||||
// __in ULONG Flags,
|
||||
// __in_opt PSID RequiredServerSid,
|
||||
// __inout PPORT_MESSAGE ConnectionMessage,
|
||||
// __inout_opt PULONG BufferLength,
|
||||
// __inout_opt PALPC_MESSAGE_ATTRIBUTES OutMessageAttributes,
|
||||
// __inout_opt PALPC_MESSAGE_ATTRIBUTES InMessageAttributes,
|
||||
// __in_opt PLARGE_INTEGER Timeout
|
||||
// );
|
||||
//func NtAlpcConnectPort(
|
||||
// destPort string,
|
||||
// pClientObjAttrs *OBJECT_ATTRIBUTES,
|
||||
// pClientAlpcPortAttrs *ALPC_PORT_ATTRIBUTES,
|
||||
// flags uint32,
|
||||
// pRequiredServerSid *SID,
|
||||
// pConnMsg *AlpcShortMessage,
|
||||
// pBufLen *uint32,
|
||||
// pOutMsgAttrs *ALPC_MESSAGE_ATTRIBUTES,
|
||||
// pInMsgAttrs *ALPC_MESSAGE_ATTRIBUTES,
|
||||
// timeout *int64,
|
||||
//) (hPort HANDLE, e error) {
|
||||
//
|
||||
// destPortU, e := newUnicodeString(destPort)
|
||||
// if e != nil {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// ret, _, _ := procNtAlpcConnectPort.Call(
|
||||
// uintptr(unsafe.Pointer(&hPort)),
|
||||
// uintptr(unsafe.Pointer(&destPortU)),
|
||||
// uintptr(unsafe.Pointer(pClientObjAttrs)),
|
||||
// uintptr(unsafe.Pointer(pClientAlpcPortAttrs)),
|
||||
// uintptr(flags),
|
||||
// uintptr(unsafe.Pointer(pRequiredServerSid)),
|
||||
// uintptr(unsafe.Pointer(pConnMsg)),
|
||||
// uintptr(unsafe.Pointer(pBufLen)),
|
||||
// uintptr(unsafe.Pointer(pOutMsgAttrs)),
|
||||
// uintptr(unsafe.Pointer(pInMsgAttrs)),
|
||||
// uintptr(unsafe.Pointer(timeout)),
|
||||
// )
|
||||
//
|
||||
// if ret != ERROR_SUCCESS {
|
||||
// e = fmt.Errorf("0x%x", ret)
|
||||
// }
|
||||
// return
|
||||
//}
|
||||
|
||||
// NTSTATUS
|
||||
// NtAlpcAcceptConnectPort(
|
||||
// __out PHANDLE PortHandle,
|
||||
// __in HANDLE ConnectionPortHandle,
|
||||
// __in ULONG Flags,
|
||||
// __in POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
// __in PALPC_PORT_ATTRIBUTES PortAttributes,
|
||||
// __in_opt PVOID PortContext,
|
||||
// __in PPORT_MESSAGE ConnectionRequest,
|
||||
// __inout_opt PALPC_MESSAGE_ATTRIBUTES ConnectionMessageAttributes,
|
||||
// __in BOOLEAN AcceptConnection
|
||||
// );
|
||||
func NtAlpcAcceptConnectPort(
|
||||
hSrvConnPort HANDLE,
|
||||
flags uint32,
|
||||
pObjAttr *OBJECT_ATTRIBUTES,
|
||||
pPortAttr *ALPC_PORT_ATTRIBUTES,
|
||||
pContext *AlpcPortContext,
|
||||
pConnReq *AlpcShortMessage,
|
||||
pConnMsgAttrs *ALPC_MESSAGE_ATTRIBUTES,
|
||||
accept uintptr,
|
||||
) (hPort HANDLE, e error) {
|
||||
|
||||
ret, _, _ := procNtAlpcAcceptConnectPort.Call(
|
||||
uintptr(unsafe.Pointer(&hPort)),
|
||||
uintptr(hSrvConnPort),
|
||||
uintptr(flags),
|
||||
uintptr(unsafe.Pointer(pObjAttr)),
|
||||
uintptr(unsafe.Pointer(pPortAttr)),
|
||||
uintptr(unsafe.Pointer(pContext)),
|
||||
uintptr(unsafe.Pointer(pConnReq)),
|
||||
uintptr(unsafe.Pointer(pConnMsgAttrs)),
|
||||
accept,
|
||||
)
|
||||
|
||||
if ret != ERROR_SUCCESS {
|
||||
e = fmt.Errorf("0x%x", ret)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NTSTATUS
|
||||
// NtAlpcSendWaitReceivePort(
|
||||
// __in HANDLE PortHandle,
|
||||
// __in ULONG Flags,
|
||||
// __in_opt PPORT_MESSAGE SendMessage,
|
||||
// __in_opt PALPC_MESSAGE_ATTRIBUTES SendMessageAttributes,
|
||||
// __inout_opt PPORT_MESSAGE ReceiveMessage,
|
||||
// __inout_opt PULONG BufferLength,
|
||||
// __inout_opt PALPC_MESSAGE_ATTRIBUTES ReceiveMessageAttributes,
|
||||
// __in_opt PLARGE_INTEGER Timeout
|
||||
// );
|
||||
func NtAlpcSendWaitReceivePort(
|
||||
hPort HANDLE,
|
||||
flags uint32,
|
||||
sendMsg *AlpcShortMessage, // Should actually point to PORT_MESSAGE + payload
|
||||
sendMsgAttrs *ALPC_MESSAGE_ATTRIBUTES,
|
||||
recvMsg *AlpcShortMessage,
|
||||
recvBufLen *uint32,
|
||||
recvMsgAttrs *ALPC_MESSAGE_ATTRIBUTES,
|
||||
timeout *int64, // use native int64
|
||||
) (e error) {
|
||||
|
||||
ret, _, _ := procNtAlpcSendWaitReceivePort.Call(
|
||||
uintptr(hPort),
|
||||
uintptr(flags),
|
||||
uintptr(unsafe.Pointer(sendMsg)),
|
||||
uintptr(unsafe.Pointer(sendMsgAttrs)),
|
||||
uintptr(unsafe.Pointer(recvMsg)),
|
||||
uintptr(unsafe.Pointer(recvBufLen)),
|
||||
uintptr(unsafe.Pointer(recvMsgAttrs)),
|
||||
uintptr(unsafe.Pointer(timeout)),
|
||||
)
|
||||
|
||||
if ret != ERROR_SUCCESS {
|
||||
e = fmt.Errorf("0x%x", ret)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NTSYSAPI
|
||||
// PVOID
|
||||
// NTAPI
|
||||
// AlpcGetMessageAttribute(
|
||||
// __in PALPC_MESSAGE_ATTRIBUTES Buffer,
|
||||
// __in ULONG AttributeFlag
|
||||
// );
|
||||
|
||||
// This basically returns a pointer to the correct struct for whichever
|
||||
// message attribute you asked for. In Go terms, it returns unsafe.Pointer
|
||||
// which you should then cast. Example:
|
||||
|
||||
// ptr := AlpcGetMessageAttribute(&recvMsgAttrs, ALPC_MESSAGE_CONTEXT_ATTRIBUTE)
|
||||
// if ptr != nil {
|
||||
// context := (*ALPC_CONTEXT_ATTR)(ptr)
|
||||
// }
|
||||
func AlpcGetMessageAttribute(buf *ALPC_MESSAGE_ATTRIBUTES, attr uint32) unsafe.Pointer {
|
||||
|
||||
ret, _, _ := procAlpcGetMessageAttribute.Call(
|
||||
uintptr(unsafe.Pointer(buf)),
|
||||
uintptr(attr),
|
||||
)
|
||||
return unsafe.Pointer(ret)
|
||||
}
|
||||
|
||||
// NTSYSCALLAPI
|
||||
// NTSTATUS
|
||||
// NTAPI
|
||||
// NtAlpcCancelMessage(
|
||||
// __in HANDLE PortHandle,
|
||||
// __in ULONG Flags,
|
||||
// __in PALPC_CONTEXT_ATTR MessageContext
|
||||
// );
|
||||
func NtAlpcCancelMessage(hPort HANDLE, flags uint32, pMsgContext *ALPC_CONTEXT_ATTR) (e error) {
|
||||
|
||||
ret, _, _ := procNtAlpcCancelMessage.Call(
|
||||
uintptr(hPort),
|
||||
uintptr(flags),
|
||||
uintptr(unsafe.Pointer(pMsgContext)),
|
||||
)
|
||||
|
||||
if ret != ERROR_SUCCESS {
|
||||
e = fmt.Errorf("0x%x", ret)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NTSYSCALLAPI
|
||||
// NTSTATUS
|
||||
// NTAPI
|
||||
// NtAlpcDisconnectPort(
|
||||
// __in HANDLE PortHandle,
|
||||
// __in ULONG Flags
|
||||
// );
|
||||
func NtAlpcDisconnectPort(hPort HANDLE, flags uint32) (e error) {
|
||||
|
||||
ret, _, _ := procNtAlpcDisconnectPort.Call(
|
||||
uintptr(hPort),
|
||||
uintptr(flags),
|
||||
)
|
||||
|
||||
if ret != ERROR_SUCCESS {
|
||||
e = fmt.Errorf("0x%x", ret)
|
||||
}
|
||||
return
|
||||
}
|
||||
64
vendor/github.com/apenwarr/w32/alpc_constants.go
generated
vendored
Normal file
64
vendor/github.com/apenwarr/w32/alpc_constants.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
package w32
|
||||
|
||||
const (
|
||||
ALPC_PORFLG_ALLOW_LPC_REQUESTS = 0x20000
|
||||
ALPC_PORFLG_SYSTEM_PROCESS = 0x100000
|
||||
ALPC_PORFLG_WAITABLE_PORT = 0x40000
|
||||
)
|
||||
|
||||
const (
|
||||
ALPC_MSGFLG_REPLY_MESSAGE = 0x1
|
||||
ALPC_MSGFLG_LPC_MODE = 0x2 // ?
|
||||
ALPC_MSGFLG_RELEASE_MESSAGE = 0x10000 // dbg
|
||||
ALPC_MSGFLG_SYNC_REQUEST = 0x20000 // dbg
|
||||
ALPC_MSGFLG_WAIT_USER_MODE = 0x100000
|
||||
ALPC_MSGFLG_WAIT_ALERTABLE = 0x200000
|
||||
ALPC_MSGFLG_WOW64_CALL = 0x80000000 // dbg
|
||||
)
|
||||
const (
|
||||
ALPC_MESSAGE_SECURITY_ATTRIBUTE = 0x80000000
|
||||
ALPC_MESSAGE_VIEW_ATTRIBUTE = 0x40000000
|
||||
ALPC_MESSAGE_CONTEXT_ATTRIBUTE = 0x20000000
|
||||
ALPC_MESSAGE_HANDLE_ATTRIBUTE = 0x10000000
|
||||
)
|
||||
|
||||
const (
|
||||
OBJ_INHERIT = 0x00000002
|
||||
OBJ_PERMANENT = 0x00000010
|
||||
OBJ_EXCLUSIVE = 0x00000020
|
||||
OBJ_CASE_INSENSITIVE = 0x00000040
|
||||
OBJ_OPENIF = 0x00000080
|
||||
OBJ_OPENLINK = 0x00000100
|
||||
OBJ_KERNEL_HANDLE = 0x00000200
|
||||
)
|
||||
|
||||
const (
|
||||
LPC_REQUEST = 1
|
||||
LPC_REPLY = 2
|
||||
LPC_DATAGRAM = 3
|
||||
LPC_LOST_REPLY = 4
|
||||
LPC_PORT_CLOSED = 5
|
||||
LPC_CLIENT_DIED = 6
|
||||
LPC_EXCEPTION = 7
|
||||
LPC_DEBUG_EVENT = 8
|
||||
LPC_ERROR_EVENT = 9
|
||||
LPC_CONNECTION_REQUEST = 10
|
||||
LPC_CONTINUATION_REQUIRED = 0x2000
|
||||
)
|
||||
|
||||
const (
|
||||
SecurityAnonymous uint32 = 1
|
||||
SecurityIdentification uint32 = 2
|
||||
SecurityImpersonation uint32 = 3
|
||||
SecurityDelegation uint32 = 4
|
||||
)
|
||||
|
||||
const (
|
||||
SECURITY_DYNAMIC_TRACKING byte = 1
|
||||
SECURITY_STATIC_TRACKING byte = 0
|
||||
)
|
||||
|
||||
const (
|
||||
ALPC_SYNC_OBJECT_TYPE uint32 = 2
|
||||
ALPC_THREAD_OBJECT_TYPE uint32 = 4
|
||||
)
|
||||
181
vendor/github.com/apenwarr/w32/alpc_typedef.go
generated
vendored
Normal file
181
vendor/github.com/apenwarr/w32/alpc_typedef.go
generated
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
package w32
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// nt!_ALPC_MESSAGE_ATTRIBUTES
|
||||
// +0x000 AllocatedAttributes : Uint4B
|
||||
// +0x004 ValidAttributes : Uint4B
|
||||
type ALPC_MESSAGE_ATTRIBUTES struct {
|
||||
AllocatedAttributes uint32
|
||||
ValidAttributes uint32
|
||||
}
|
||||
|
||||
type ALPC_CONTEXT_ATTR struct {
|
||||
PortContext *AlpcPortContext
|
||||
MessageContext uintptr
|
||||
Sequence uint32
|
||||
MessageId uint32
|
||||
CallbackId uint32
|
||||
}
|
||||
|
||||
type ALPC_HANDLE_ATTR struct {
|
||||
Flags uint32
|
||||
Handle HANDLE
|
||||
ObjectType uint32
|
||||
DesiredAccess uint32
|
||||
}
|
||||
|
||||
// nt!_CLIENT_ID
|
||||
// +0x000 UniqueProcess : Ptr64 Void
|
||||
// +0x008 UniqueThread : Ptr64 Void
|
||||
type CLIENT_ID struct {
|
||||
UniqueProcess uintptr
|
||||
UniqueThread uintptr
|
||||
}
|
||||
|
||||
// nt!_UNICODE_STRING
|
||||
// +0x000 Length : Uint2B
|
||||
// +0x002 MaximumLength : Uint2B
|
||||
// +0x008 Buffer : Ptr64 Uint2B
|
||||
type UNICODE_STRING struct {
|
||||
Length uint16
|
||||
MaximumLength uint16
|
||||
_ [4]byte // align to 0x08
|
||||
Buffer *uint16
|
||||
}
|
||||
|
||||
// nt!_OBJECT_ATTRIBUTES
|
||||
// +0x000 Length : Uint4B
|
||||
// +0x008 RootDirectory : Ptr64 Void
|
||||
// +0x010 ObjectName : Ptr64 _UNICODE_STRING
|
||||
// +0x018 Attributes : Uint4B
|
||||
// +0x020 SecurityDescriptor : Ptr64 Void
|
||||
// +0x028 SecurityQualityOfService : Ptr64 Void
|
||||
type OBJECT_ATTRIBUTES struct {
|
||||
Length uint32
|
||||
_ [4]byte // align to 0x08
|
||||
RootDirectory HANDLE
|
||||
ObjectName *UNICODE_STRING
|
||||
Attributes uint32
|
||||
_ [4]byte // align to 0x20
|
||||
SecurityDescriptor *SECURITY_DESCRIPTOR
|
||||
SecurityQualityOfService *SECURITY_QUALITY_OF_SERVICE
|
||||
}
|
||||
|
||||
// cf: http://j00ru.vexillium.org/?p=502 for legacy RPC
|
||||
// nt!_PORT_MESSAGE
|
||||
// +0x000 u1 : <unnamed-tag>
|
||||
// +0x004 u2 : <unnamed-tag>
|
||||
// +0x008 ClientId : _CLIENT_ID
|
||||
// +0x008 DoNotUseThisField : Float
|
||||
// +0x018 MessageId : Uint4B
|
||||
// +0x020 ClientViewSize : Uint8B
|
||||
// +0x020 CallbackId : Uint4B
|
||||
type PORT_MESSAGE struct {
|
||||
DataLength uint16 // These are the two unnamed unions
|
||||
TotalLength uint16 // without Length and ZeroInit
|
||||
Type uint16
|
||||
DataInfoOffset uint16
|
||||
ClientId CLIENT_ID
|
||||
MessageId uint32
|
||||
_ [4]byte // align up to 0x20
|
||||
ClientViewSize uint64
|
||||
}
|
||||
|
||||
func (pm PORT_MESSAGE) CallbackId() uint32 {
|
||||
return uint32(pm.ClientViewSize >> 32)
|
||||
}
|
||||
|
||||
func (pm PORT_MESSAGE) DoNotUseThisField() float64 {
|
||||
panic("WE TOLD YOU NOT TO USE THIS FIELD")
|
||||
}
|
||||
|
||||
const PORT_MESSAGE_SIZE = 0x28
|
||||
|
||||
// http://www.nirsoft.net/kernel_struct/vista/SECURITY_QUALITY_OF_SERVICE.html
|
||||
type SECURITY_QUALITY_OF_SERVICE struct {
|
||||
Length uint32
|
||||
ImpersonationLevel uint32
|
||||
ContextTrackingMode byte
|
||||
EffectiveOnly byte
|
||||
_ [2]byte // align to 12 bytes
|
||||
}
|
||||
|
||||
const SECURITY_QOS_SIZE = 12
|
||||
|
||||
// nt!_ALPC_PORT_ATTRIBUTES
|
||||
// +0x000 Flags : Uint4B
|
||||
// +0x004 SecurityQos : _SECURITY_QUALITY_OF_SERVICE
|
||||
// +0x010 MaxMessageLength : Uint8B
|
||||
// +0x018 MemoryBandwidth : Uint8B
|
||||
// +0x020 MaxPoolUsage : Uint8B
|
||||
// +0x028 MaxSectionSize : Uint8B
|
||||
// +0x030 MaxViewSize : Uint8B
|
||||
// +0x038 MaxTotalSectionSize : Uint8B
|
||||
// +0x040 DupObjectTypes : Uint4B
|
||||
// +0x044 Reserved : Uint4B
|
||||
type ALPC_PORT_ATTRIBUTES struct {
|
||||
Flags uint32
|
||||
SecurityQos SECURITY_QUALITY_OF_SERVICE
|
||||
MaxMessageLength uint64 // must be filled out
|
||||
MemoryBandwidth uint64
|
||||
MaxPoolUsage uint64
|
||||
MaxSectionSize uint64
|
||||
MaxViewSize uint64
|
||||
MaxTotalSectionSize uint64
|
||||
DupObjectTypes uint32
|
||||
Reserved uint32
|
||||
}
|
||||
|
||||
const SHORT_MESSAGE_MAX_SIZE uint16 = 65535 // MAX_USHORT
|
||||
const SHORT_MESSAGE_MAX_PAYLOAD uint16 = SHORT_MESSAGE_MAX_SIZE - PORT_MESSAGE_SIZE
|
||||
|
||||
// LPC uses the first 4 bytes of the payload as an LPC Command, but this is
|
||||
// NOT represented here, to allow the use of raw ALPC. For legacy LPC, callers
|
||||
// must include the command as part of their payload.
|
||||
type AlpcShortMessage struct {
|
||||
PORT_MESSAGE
|
||||
Data [SHORT_MESSAGE_MAX_PAYLOAD]byte
|
||||
}
|
||||
|
||||
func NewAlpcShortMessage() AlpcShortMessage {
|
||||
sm := AlpcShortMessage{}
|
||||
sm.TotalLength = SHORT_MESSAGE_MAX_SIZE
|
||||
return sm
|
||||
}
|
||||
|
||||
func (sm *AlpcShortMessage) SetData(d []byte) (e error) {
|
||||
|
||||
copy(sm.Data[:], d)
|
||||
if len(d) > int(SHORT_MESSAGE_MAX_PAYLOAD) {
|
||||
e = errors.New("data too big - truncated")
|
||||
sm.DataLength = SHORT_MESSAGE_MAX_PAYLOAD
|
||||
sm.TotalLength = SHORT_MESSAGE_MAX_SIZE
|
||||
return
|
||||
}
|
||||
sm.TotalLength = uint16(PORT_MESSAGE_SIZE + len(d))
|
||||
sm.DataLength = uint16(len(d))
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// TODO - is this still useful?
|
||||
func (sm *AlpcShortMessage) GetData() []byte {
|
||||
if int(sm.DataLength) > int(SHORT_MESSAGE_MAX_PAYLOAD) {
|
||||
return sm.Data[:] // truncate
|
||||
}
|
||||
return sm.Data[:sm.DataLength]
|
||||
}
|
||||
|
||||
func (sm *AlpcShortMessage) Reset() {
|
||||
// zero the PORT_MESSAGE header
|
||||
sm.PORT_MESSAGE = PORT_MESSAGE{}
|
||||
sm.TotalLength = SHORT_MESSAGE_MAX_SIZE
|
||||
sm.DataLength = 0
|
||||
}
|
||||
|
||||
type AlpcPortContext struct {
|
||||
Handle HANDLE
|
||||
}
|
||||
109
vendor/github.com/apenwarr/w32/comctl32.go
generated
vendored
Normal file
109
vendor/github.com/apenwarr/w32/comctl32.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modcomctl32 = syscall.NewLazyDLL("comctl32.dll")
|
||||
|
||||
procInitCommonControlsEx = modcomctl32.NewProc("InitCommonControlsEx")
|
||||
procImageList_Create = modcomctl32.NewProc("ImageList_Create")
|
||||
procImageList_Destroy = modcomctl32.NewProc("ImageList_Destroy")
|
||||
procImageList_GetImageCount = modcomctl32.NewProc("ImageList_GetImageCount")
|
||||
procImageList_SetImageCount = modcomctl32.NewProc("ImageList_SetImageCount")
|
||||
procImageList_Add = modcomctl32.NewProc("ImageList_Add")
|
||||
procImageList_ReplaceIcon = modcomctl32.NewProc("ImageList_ReplaceIcon")
|
||||
procImageList_Remove = modcomctl32.NewProc("ImageList_Remove")
|
||||
procTrackMouseEvent = modcomctl32.NewProc("_TrackMouseEvent")
|
||||
)
|
||||
|
||||
func InitCommonControlsEx(lpInitCtrls *INITCOMMONCONTROLSEX) bool {
|
||||
ret, _, _ := procInitCommonControlsEx.Call(
|
||||
uintptr(unsafe.Pointer(lpInitCtrls)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func ImageList_Create(cx, cy int, flags uint, cInitial, cGrow int) HIMAGELIST {
|
||||
ret, _, _ := procImageList_Create.Call(
|
||||
uintptr(cx),
|
||||
uintptr(cy),
|
||||
uintptr(flags),
|
||||
uintptr(cInitial),
|
||||
uintptr(cGrow))
|
||||
|
||||
if ret == 0 {
|
||||
panic("Create image list failed")
|
||||
}
|
||||
|
||||
return HIMAGELIST(ret)
|
||||
}
|
||||
|
||||
func ImageList_Destroy(himl HIMAGELIST) bool {
|
||||
ret, _, _ := procImageList_Destroy.Call(
|
||||
uintptr(himl))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func ImageList_GetImageCount(himl HIMAGELIST) int {
|
||||
ret, _, _ := procImageList_GetImageCount.Call(
|
||||
uintptr(himl))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func ImageList_SetImageCount(himl HIMAGELIST, uNewCount uint) bool {
|
||||
ret, _, _ := procImageList_SetImageCount.Call(
|
||||
uintptr(himl),
|
||||
uintptr(uNewCount))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func ImageList_Add(himl HIMAGELIST, hbmImage, hbmMask HBITMAP) int {
|
||||
ret, _, _ := procImageList_Add.Call(
|
||||
uintptr(himl),
|
||||
uintptr(hbmImage),
|
||||
uintptr(hbmMask))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func ImageList_ReplaceIcon(himl HIMAGELIST, i int, hicon HICON) int {
|
||||
ret, _, _ := procImageList_ReplaceIcon.Call(
|
||||
uintptr(himl),
|
||||
uintptr(i),
|
||||
uintptr(hicon))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func ImageList_AddIcon(himl HIMAGELIST, hicon HICON) int {
|
||||
return ImageList_ReplaceIcon(himl, -1, hicon)
|
||||
}
|
||||
|
||||
func ImageList_Remove(himl HIMAGELIST, i int) bool {
|
||||
ret, _, _ := procImageList_Remove.Call(
|
||||
uintptr(himl),
|
||||
uintptr(i))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func ImageList_RemoveAll(himl HIMAGELIST) bool {
|
||||
return ImageList_Remove(himl, -1)
|
||||
}
|
||||
|
||||
func TrackMouseEvent(tme *TRACKMOUSEEVENT) bool {
|
||||
ret, _, _ := procTrackMouseEvent.Call(
|
||||
uintptr(unsafe.Pointer(tme)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
38
vendor/github.com/apenwarr/w32/comdlg32.go
generated
vendored
Normal file
38
vendor/github.com/apenwarr/w32/comdlg32.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modcomdlg32 = syscall.NewLazyDLL("comdlg32.dll")
|
||||
|
||||
procGetSaveFileName = modcomdlg32.NewProc("GetSaveFileNameW")
|
||||
procGetOpenFileName = modcomdlg32.NewProc("GetOpenFileNameW")
|
||||
procCommDlgExtendedError = modcomdlg32.NewProc("CommDlgExtendedError")
|
||||
)
|
||||
|
||||
func GetOpenFileName(ofn *OPENFILENAME) bool {
|
||||
ret, _, _ := procGetOpenFileName.Call(
|
||||
uintptr(unsafe.Pointer(ofn)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func GetSaveFileName(ofn *OPENFILENAME) bool {
|
||||
ret, _, _ := procGetSaveFileName.Call(
|
||||
uintptr(unsafe.Pointer(ofn)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func CommDlgExtendedError() uint {
|
||||
ret, _, _ := procCommDlgExtendedError.Call()
|
||||
|
||||
return uint(ret)
|
||||
}
|
||||
2628
vendor/github.com/apenwarr/w32/constants.go
generated
vendored
Normal file
2628
vendor/github.com/apenwarr/w32/constants.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
152
vendor/github.com/apenwarr/w32/create_process.go
generated
vendored
Normal file
152
vendor/github.com/apenwarr/w32/create_process.go
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
procCreateProcessW = kernel32.NewProc("CreateProcessW")
|
||||
procTerminateProcess = kernel32.NewProc("TerminateProcess")
|
||||
procGetExitCodeProcess = kernel32.NewProc("GetExitCodeProcess")
|
||||
procWaitForSingleObject = kernel32.NewProc("WaitForSingleObject")
|
||||
)
|
||||
|
||||
// WINBASEAPI WINBOOL WINAPI
|
||||
// CreateProcessW (
|
||||
// LPCWSTR lpApplicationName,
|
||||
// LPWSTR lpCommandLine,
|
||||
// LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
// LPSECURITY_ATTRIBUTES lpThreadAttributes
|
||||
// WINBOOL bInheritHandles
|
||||
// DWORD dwCreationFlags
|
||||
// LPVOID lpEnvironment
|
||||
// LPCWSTR lpCurrentDirectory
|
||||
// LPSTARTUPINFOW lpStartupInfo
|
||||
// LPPROCESS_INFORMATION lpProcessInformation
|
||||
//);
|
||||
func CreateProcessW(
|
||||
lpApplicationName, lpCommandLine string,
|
||||
lpProcessAttributes, lpThreadAttributes *SECURITY_ATTRIBUTES,
|
||||
bInheritHandles BOOL,
|
||||
dwCreationFlags uint32,
|
||||
lpEnvironment unsafe.Pointer,
|
||||
lpCurrentDirectory string,
|
||||
lpStartupInfo *STARTUPINFOW,
|
||||
lpProcessInformation *PROCESS_INFORMATION,
|
||||
) (e error) {
|
||||
|
||||
var lpAN, lpCL, lpCD *uint16
|
||||
if len(lpApplicationName) > 0 {
|
||||
lpAN, e = syscall.UTF16PtrFromString(lpApplicationName)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(lpCommandLine) > 0 {
|
||||
lpCL, e = syscall.UTF16PtrFromString(lpCommandLine)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(lpCurrentDirectory) > 0 {
|
||||
lpCD, e = syscall.UTF16PtrFromString(lpCurrentDirectory)
|
||||
if e != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ret, _, lastErr := procCreateProcessW.Call(
|
||||
uintptr(unsafe.Pointer(lpAN)),
|
||||
uintptr(unsafe.Pointer(lpCL)),
|
||||
uintptr(unsafe.Pointer(lpProcessAttributes)),
|
||||
uintptr(unsafe.Pointer(lpProcessInformation)),
|
||||
uintptr(bInheritHandles),
|
||||
uintptr(dwCreationFlags),
|
||||
uintptr(lpEnvironment),
|
||||
uintptr(unsafe.Pointer(lpCD)),
|
||||
uintptr(unsafe.Pointer(lpStartupInfo)),
|
||||
uintptr(unsafe.Pointer(lpProcessInformation)),
|
||||
)
|
||||
|
||||
if ret == 0 {
|
||||
e = lastErr
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func CreateProcessQuick(cmd string) (pi PROCESS_INFORMATION, e error) {
|
||||
si := &STARTUPINFOW{}
|
||||
e = CreateProcessW(
|
||||
"",
|
||||
cmd,
|
||||
nil,
|
||||
nil,
|
||||
0,
|
||||
0,
|
||||
unsafe.Pointer(nil),
|
||||
"",
|
||||
si,
|
||||
&pi,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
func TerminateProcess(hProcess HANDLE, exitCode uint32) (e error) {
|
||||
ret, _, lastErr := procTerminateProcess.Call(
|
||||
uintptr(hProcess),
|
||||
uintptr(exitCode),
|
||||
)
|
||||
|
||||
if ret == 0 {
|
||||
e = lastErr
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func GetExitCodeProcess(hProcess HANDLE) (code uintptr, e error) {
|
||||
ret, _, lastErr := procGetExitCodeProcess.Call(
|
||||
uintptr(hProcess),
|
||||
uintptr(unsafe.Pointer(&code)),
|
||||
)
|
||||
|
||||
if ret == 0 {
|
||||
e = lastErr
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DWORD WINAPI WaitForSingleObject(
|
||||
// _In_ HANDLE hHandle,
|
||||
// _In_ DWORD dwMilliseconds
|
||||
// );
|
||||
|
||||
func WaitForSingleObject(hHandle HANDLE, msecs uint32) (ok bool, e error) {
|
||||
|
||||
ret, _, lastErr := procWaitForSingleObject.Call(
|
||||
uintptr(hHandle),
|
||||
uintptr(msecs),
|
||||
)
|
||||
|
||||
if ret == WAIT_OBJECT_0 {
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
// don't set e for timeouts, or it will be ERROR_SUCCESS which is
|
||||
// confusing
|
||||
if ret != WAIT_TIMEOUT {
|
||||
e = lastErr
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
9
vendor/github.com/apenwarr/w32/create_process_constants.go
generated
vendored
Normal file
9
vendor/github.com/apenwarr/w32/create_process_constants.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package w32
|
||||
|
||||
const (
|
||||
WAIT_ABANDONED = 0x00000080
|
||||
WAIT_OBJECT_0 = 0x00000000
|
||||
WAIT_TIMEOUT = 0x00000102
|
||||
WAIT_FAILED = 0xFFFFFFFF
|
||||
INFINITE = 0xFFFFFFFF
|
||||
)
|
||||
68
vendor/github.com/apenwarr/w32/create_process_typedef.go
generated
vendored
Normal file
68
vendor/github.com/apenwarr/w32/create_process_typedef.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
package w32
|
||||
|
||||
// typedef struct _PROCESS_INFORMATION {
|
||||
// HANDLE hProcess;
|
||||
// HANDLE hThread;
|
||||
// DWORD dwProcessId;
|
||||
// DWORD dwThreadId;
|
||||
// } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
|
||||
|
||||
type PROCESS_INFORMATION struct {
|
||||
Process HANDLE
|
||||
Thread HANDLE
|
||||
ProcessId uint32
|
||||
ThreadId uint32
|
||||
}
|
||||
|
||||
// typedef struct _STARTUPINFOW {
|
||||
// DWORD cb;
|
||||
// LPWSTR lpReserved;
|
||||
// LPWSTR lpDesktop;
|
||||
// LPWSTR lpTitle;
|
||||
// DWORD dwX;
|
||||
// DWORD dwY;
|
||||
// DWORD dwXSize;
|
||||
// DWORD dwYSize;
|
||||
// DWORD dwXCountChars;
|
||||
// DWORD dwYCountChars;
|
||||
// DWORD dwFillAttribute;
|
||||
// DWORD dwFlags;
|
||||
// WORD wShowWindow;
|
||||
// WORD cbReserved2;
|
||||
// LPBYTE lpReserved2;
|
||||
// HANDLE hStdInput;
|
||||
// HANDLE hStdOutput;
|
||||
// HANDLE hStdError;
|
||||
// } STARTUPINFOW, *LPSTARTUPINFOW;
|
||||
|
||||
type STARTUPINFOW struct {
|
||||
cb uint32
|
||||
_ *uint16
|
||||
Desktop *uint16
|
||||
Title *uint16
|
||||
X uint32
|
||||
Y uint32
|
||||
XSize uint32
|
||||
YSize uint32
|
||||
XCountChars uint32
|
||||
YCountChars uint32
|
||||
FillAttribute uint32
|
||||
Flags uint32
|
||||
ShowWindow uint16
|
||||
_ uint16
|
||||
_ *uint8
|
||||
StdInput HANDLE
|
||||
StdOutput HANDLE
|
||||
StdError HANDLE
|
||||
}
|
||||
|
||||
// combase!_SECURITY_ATTRIBUTES
|
||||
// +0x000 nLength : Uint4B
|
||||
// +0x008 lpSecurityDescriptor : Ptr64 Void
|
||||
// +0x010 bInheritHandle : Int4B
|
||||
|
||||
type SECURITY_ATTRIBUTES struct {
|
||||
Length uint32
|
||||
SecurityDescriptor uintptr
|
||||
InheritHandle BOOL
|
||||
}
|
||||
254
vendor/github.com/apenwarr/w32/dwmapi.go
generated
vendored
Normal file
254
vendor/github.com/apenwarr/w32/dwmapi.go
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// DEFINED IN THE DWM API BUT NOT IMPLEMENTED BY MS:
|
||||
// DwmAttachMilContent
|
||||
// DwmDetachMilContent
|
||||
// DwmEnableComposition
|
||||
// DwmGetGraphicsStreamClient
|
||||
// DwmGetGraphicsStreamTransformHint
|
||||
|
||||
var (
|
||||
moddwmapi = syscall.NewLazyDLL("dwmapi.dll")
|
||||
|
||||
procDwmDefWindowProc = moddwmapi.NewProc("DwmDefWindowProc")
|
||||
procDwmEnableBlurBehindWindow = moddwmapi.NewProc("DwmEnableBlurBehindWindow")
|
||||
procDwmEnableMMCSS = moddwmapi.NewProc("DwmEnableMMCSS")
|
||||
procDwmExtendFrameIntoClientArea = moddwmapi.NewProc("DwmExtendFrameIntoClientArea")
|
||||
procDwmFlush = moddwmapi.NewProc("DwmFlush")
|
||||
procDwmGetColorizationColor = moddwmapi.NewProc("DwmGetColorizationColor")
|
||||
procDwmGetCompositionTimingInfo = moddwmapi.NewProc("DwmGetCompositionTimingInfo")
|
||||
procDwmGetTransportAttributes = moddwmapi.NewProc("DwmGetTransportAttributes")
|
||||
procDwmGetWindowAttribute = moddwmapi.NewProc("DwmGetWindowAttribute")
|
||||
procDwmInvalidateIconicBitmaps = moddwmapi.NewProc("DwmInvalidateIconicBitmaps")
|
||||
procDwmIsCompositionEnabled = moddwmapi.NewProc("DwmIsCompositionEnabled")
|
||||
procDwmModifyPreviousDxFrameDuration = moddwmapi.NewProc("DwmModifyPreviousDxFrameDuration")
|
||||
procDwmQueryThumbnailSourceSize = moddwmapi.NewProc("DwmQueryThumbnailSourceSize")
|
||||
procDwmRegisterThumbnail = moddwmapi.NewProc("DwmRegisterThumbnail")
|
||||
procDwmRenderGesture = moddwmapi.NewProc("DwmRenderGesture")
|
||||
procDwmSetDxFrameDuration = moddwmapi.NewProc("DwmSetDxFrameDuration")
|
||||
procDwmSetIconicLivePreviewBitmap = moddwmapi.NewProc("DwmSetIconicLivePreviewBitmap")
|
||||
procDwmSetIconicThumbnail = moddwmapi.NewProc("DwmSetIconicThumbnail")
|
||||
procDwmSetPresentParameters = moddwmapi.NewProc("DwmSetPresentParameters")
|
||||
procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute")
|
||||
procDwmShowContact = moddwmapi.NewProc("DwmShowContact")
|
||||
procDwmTetherContact = moddwmapi.NewProc("DwmTetherContact")
|
||||
procDwmTransitionOwnedWindow = moddwmapi.NewProc("DwmTransitionOwnedWindow")
|
||||
procDwmUnregisterThumbnail = moddwmapi.NewProc("DwmUnregisterThumbnail")
|
||||
procDwmUpdateThumbnailProperties = moddwmapi.NewProc("DwmUpdateThumbnailProperties")
|
||||
)
|
||||
|
||||
func DwmDefWindowProc(hWnd HWND, msg uint, wParam, lParam uintptr) (bool, uint) {
|
||||
var result uint
|
||||
ret, _, _ := procDwmDefWindowProc.Call(
|
||||
uintptr(hWnd),
|
||||
uintptr(msg),
|
||||
wParam,
|
||||
lParam,
|
||||
uintptr(unsafe.Pointer(&result)))
|
||||
return ret != 0, result
|
||||
}
|
||||
|
||||
func DwmEnableBlurBehindWindow(hWnd HWND, pBlurBehind *DWM_BLURBEHIND) HRESULT {
|
||||
ret, _, _ := procDwmEnableBlurBehindWindow.Call(
|
||||
uintptr(hWnd),
|
||||
uintptr(unsafe.Pointer(pBlurBehind)))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmEnableMMCSS(fEnableMMCSS bool) HRESULT {
|
||||
ret, _, _ := procDwmEnableMMCSS.Call(
|
||||
uintptr(BoolToBOOL(fEnableMMCSS)))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmExtendFrameIntoClientArea(hWnd HWND, pMarInset *MARGINS) HRESULT {
|
||||
ret, _, _ := procDwmExtendFrameIntoClientArea.Call(
|
||||
uintptr(hWnd),
|
||||
uintptr(unsafe.Pointer(pMarInset)))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmFlush() HRESULT {
|
||||
ret, _, _ := procDwmFlush.Call()
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmGetColorizationColor(pcrColorization *uint32, pfOpaqueBlend *BOOL) HRESULT {
|
||||
ret, _, _ := procDwmGetColorizationColor.Call(
|
||||
uintptr(unsafe.Pointer(pcrColorization)),
|
||||
uintptr(unsafe.Pointer(pfOpaqueBlend)))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmGetCompositionTimingInfo(hWnd HWND, pTimingInfo *DWM_TIMING_INFO) HRESULT {
|
||||
ret, _, _ := procDwmGetCompositionTimingInfo.Call(
|
||||
uintptr(hWnd),
|
||||
uintptr(unsafe.Pointer(pTimingInfo)))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmGetTransportAttributes(pfIsRemoting *BOOL, pfIsConnected *BOOL, pDwGeneration *uint32) HRESULT {
|
||||
ret, _, _ := procDwmGetTransportAttributes.Call(
|
||||
uintptr(unsafe.Pointer(pfIsRemoting)),
|
||||
uintptr(unsafe.Pointer(pfIsConnected)),
|
||||
uintptr(unsafe.Pointer(pDwGeneration)))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
// TODO: verify handling of variable arguments
|
||||
func DwmGetWindowAttribute(hWnd HWND, dwAttribute uint32) (pAttribute interface{}, result HRESULT) {
|
||||
var pvAttribute, pvAttrSize uintptr
|
||||
switch dwAttribute {
|
||||
case DWMWA_NCRENDERING_ENABLED:
|
||||
v := new(BOOL)
|
||||
pAttribute = v
|
||||
pvAttribute = uintptr(unsafe.Pointer(v))
|
||||
pvAttrSize = unsafe.Sizeof(*v)
|
||||
case DWMWA_CAPTION_BUTTON_BOUNDS, DWMWA_EXTENDED_FRAME_BOUNDS:
|
||||
v := new(RECT)
|
||||
pAttribute = v
|
||||
pvAttribute = uintptr(unsafe.Pointer(v))
|
||||
pvAttrSize = unsafe.Sizeof(*v)
|
||||
case DWMWA_CLOAKED:
|
||||
panic(fmt.Sprintf("DwmGetWindowAttribute(%d) is not currently supported.", dwAttribute))
|
||||
default:
|
||||
panic(fmt.Sprintf("DwmGetWindowAttribute(%d) is not valid.", dwAttribute))
|
||||
}
|
||||
|
||||
ret, _, _ := procDwmGetWindowAttribute.Call(
|
||||
uintptr(hWnd),
|
||||
uintptr(dwAttribute),
|
||||
pvAttribute,
|
||||
pvAttrSize)
|
||||
result = HRESULT(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func DwmInvalidateIconicBitmaps(hWnd HWND) HRESULT {
|
||||
ret, _, _ := procDwmInvalidateIconicBitmaps.Call(
|
||||
uintptr(hWnd))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmIsCompositionEnabled(pfEnabled *BOOL) HRESULT {
|
||||
ret, _, _ := procDwmIsCompositionEnabled.Call(
|
||||
uintptr(unsafe.Pointer(pfEnabled)))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmModifyPreviousDxFrameDuration(hWnd HWND, cRefreshes int, fRelative bool) HRESULT {
|
||||
ret, _, _ := procDwmModifyPreviousDxFrameDuration.Call(
|
||||
uintptr(hWnd),
|
||||
uintptr(cRefreshes),
|
||||
uintptr(BoolToBOOL(fRelative)))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmQueryThumbnailSourceSize(hThumbnail HTHUMBNAIL, pSize *SIZE) HRESULT {
|
||||
ret, _, _ := procDwmQueryThumbnailSourceSize.Call(
|
||||
uintptr(hThumbnail),
|
||||
uintptr(unsafe.Pointer(pSize)))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmRegisterThumbnail(hWndDestination HWND, hWndSource HWND, phThumbnailId *HTHUMBNAIL) HRESULT {
|
||||
ret, _, _ := procDwmRegisterThumbnail.Call(
|
||||
uintptr(hWndDestination),
|
||||
uintptr(hWndSource),
|
||||
uintptr(unsafe.Pointer(phThumbnailId)))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmRenderGesture(gt GESTURE_TYPE, cContacts uint, pdwPointerID *uint32, pPoints *POINT) {
|
||||
procDwmRenderGesture.Call(
|
||||
uintptr(gt),
|
||||
uintptr(cContacts),
|
||||
uintptr(unsafe.Pointer(pdwPointerID)),
|
||||
uintptr(unsafe.Pointer(pPoints)))
|
||||
return
|
||||
}
|
||||
|
||||
func DwmSetDxFrameDuration(hWnd HWND, cRefreshes int) HRESULT {
|
||||
ret, _, _ := procDwmSetDxFrameDuration.Call(
|
||||
uintptr(hWnd),
|
||||
uintptr(cRefreshes))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmSetIconicLivePreviewBitmap(hWnd HWND, hbmp HBITMAP, pptClient *POINT, dwSITFlags uint32) HRESULT {
|
||||
ret, _, _ := procDwmSetIconicLivePreviewBitmap.Call(
|
||||
uintptr(hWnd),
|
||||
uintptr(hbmp),
|
||||
uintptr(unsafe.Pointer(pptClient)),
|
||||
uintptr(dwSITFlags))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmSetIconicThumbnail(hWnd HWND, hbmp HBITMAP, dwSITFlags uint32) HRESULT {
|
||||
ret, _, _ := procDwmSetIconicThumbnail.Call(
|
||||
uintptr(hWnd),
|
||||
uintptr(hbmp),
|
||||
uintptr(dwSITFlags))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmSetPresentParameters(hWnd HWND, pPresentParams *DWM_PRESENT_PARAMETERS) HRESULT {
|
||||
ret, _, _ := procDwmSetPresentParameters.Call(
|
||||
uintptr(hWnd),
|
||||
uintptr(unsafe.Pointer(pPresentParams)))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmSetWindowAttribute(hWnd HWND, dwAttribute uint32, pvAttribute LPCVOID, cbAttribute uint32) HRESULT {
|
||||
ret, _, _ := procDwmSetWindowAttribute.Call(
|
||||
uintptr(hWnd),
|
||||
uintptr(dwAttribute),
|
||||
uintptr(pvAttribute),
|
||||
uintptr(cbAttribute))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmShowContact(dwPointerID uint32, eShowContact DWM_SHOWCONTACT) {
|
||||
procDwmShowContact.Call(
|
||||
uintptr(dwPointerID),
|
||||
uintptr(eShowContact))
|
||||
return
|
||||
}
|
||||
|
||||
func DwmTetherContact(dwPointerID uint32, fEnable bool, ptTether POINT) {
|
||||
procDwmTetherContact.Call(
|
||||
uintptr(dwPointerID),
|
||||
uintptr(BoolToBOOL(fEnable)),
|
||||
uintptr(unsafe.Pointer(&ptTether)))
|
||||
return
|
||||
}
|
||||
|
||||
func DwmTransitionOwnedWindow(hWnd HWND, target DWMTRANSITION_OWNEDWINDOW_TARGET) {
|
||||
procDwmTransitionOwnedWindow.Call(
|
||||
uintptr(hWnd),
|
||||
uintptr(target))
|
||||
return
|
||||
}
|
||||
|
||||
func DwmUnregisterThumbnail(hThumbnailId HTHUMBNAIL) HRESULT {
|
||||
ret, _, _ := procDwmUnregisterThumbnail.Call(
|
||||
uintptr(hThumbnailId))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func DwmUpdateThumbnailProperties(hThumbnailId HTHUMBNAIL, ptnProperties *DWM_THUMBNAIL_PROPERTIES) HRESULT {
|
||||
ret, _, _ := procDwmUpdateThumbnailProperties.Call(
|
||||
uintptr(hThumbnailId),
|
||||
uintptr(unsafe.Pointer(ptnProperties)))
|
||||
return HRESULT(ret)
|
||||
}
|
||||
174
vendor/github.com/apenwarr/w32/fork.go
generated
vendored
Normal file
174
vendor/github.com/apenwarr/w32/fork.go
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
// #include <stdlib.h>
|
||||
//import (
|
||||
// "C"
|
||||
//)
|
||||
|
||||
// Based on C code found here https://gist.github.com/juntalis/4366916
|
||||
// Original code license:
|
||||
/*
|
||||
* fork.c
|
||||
* Experimental fork() on Windows. Requires NT 6 subsystem or
|
||||
* newer.
|
||||
*
|
||||
* Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* This software is provided 'as is' and without any warranty, express or
|
||||
* implied. In no event shall the authors be liable for any damages arising
|
||||
* from the use of this software.
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
ntdll = syscall.NewLazyDLL("ntdll.dll")
|
||||
|
||||
procRtlCloneUserProcess = ntdll.NewProc("RtlCloneUserProcess")
|
||||
procAllocConsole = modkernel32.NewProc("AllocConsole")
|
||||
procOpenProcess = modkernel32.NewProc("OpenProcess")
|
||||
procOpenThread = modkernel32.NewProc("OpenThread")
|
||||
procResumeThread = modkernel32.NewProc("ResumeThread")
|
||||
)
|
||||
|
||||
func OpenProcess(desiredAccess int, inheritHandle bool, processId uintptr) (h HANDLE, e error) {
|
||||
inherit := uintptr(0)
|
||||
if inheritHandle {
|
||||
inherit = 1
|
||||
}
|
||||
|
||||
ret, _, lastErr := procOpenProcess.Call(
|
||||
uintptr(desiredAccess),
|
||||
inherit,
|
||||
uintptr(processId),
|
||||
)
|
||||
|
||||
if ret == 0 {
|
||||
e = lastErr
|
||||
}
|
||||
|
||||
h = HANDLE(ret)
|
||||
return
|
||||
}
|
||||
|
||||
func OpenThread(desiredAccess int, inheritHandle bool, threadId uintptr) (h HANDLE, e error) {
|
||||
inherit := uintptr(0)
|
||||
if inheritHandle {
|
||||
inherit = 1
|
||||
}
|
||||
|
||||
ret, _, lastErr := procOpenThread.Call(
|
||||
uintptr(desiredAccess),
|
||||
inherit,
|
||||
uintptr(threadId),
|
||||
)
|
||||
|
||||
if ret == 0 {
|
||||
e = lastErr
|
||||
}
|
||||
|
||||
h = HANDLE(ret)
|
||||
return
|
||||
}
|
||||
|
||||
// DWORD WINAPI ResumeThread(
|
||||
// _In_ HANDLE hThread
|
||||
// );
|
||||
func ResumeThread(ht HANDLE) (e error) {
|
||||
|
||||
ret, _, lastErr := procResumeThread.Call(
|
||||
uintptr(ht),
|
||||
)
|
||||
if ret == ^uintptr(0) { // -1
|
||||
e = lastErr
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// BOOL WINAPI AllocConsole(void);
|
||||
func AllocConsole() (e error) {
|
||||
ret, _, lastErr := procAllocConsole.Call()
|
||||
if ret != ERROR_SUCCESS {
|
||||
e = lastErr
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NTSYSAPI
|
||||
// NTSTATUS
|
||||
// NTAPI RtlCloneUserProcess (
|
||||
// _In_ ULONG ProcessFlags,
|
||||
// _In_opt_ PSECURITY_DESCRIPTOR ProcessSecurityDescriptor,
|
||||
// _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,
|
||||
// _In_opt_ HANDLE DebugPort,
|
||||
// _Out_ PRTL_USER_PROCESS_INFORMATION ProcessInformation
|
||||
// )
|
||||
|
||||
func RtlCloneUserProcess(
|
||||
ProcessFlags uint32,
|
||||
ProcessSecurityDescriptor, ThreadSecurityDescriptor *SECURITY_DESCRIPTOR, // in advapi32_typedef.go
|
||||
DebugPort HANDLE,
|
||||
ProcessInformation *RTL_USER_PROCESS_INFORMATION,
|
||||
) (status uintptr) {
|
||||
|
||||
status, _, _ = procRtlCloneUserProcess.Call(
|
||||
uintptr(ProcessFlags),
|
||||
uintptr(unsafe.Pointer(ProcessSecurityDescriptor)),
|
||||
uintptr(unsafe.Pointer(ThreadSecurityDescriptor)),
|
||||
uintptr(DebugPort),
|
||||
uintptr(unsafe.Pointer(ProcessInformation)),
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Fork creates a clone of the current process using the undocumented
|
||||
// RtlCloneUserProcess call in ntdll, similar to unix fork(). The
|
||||
// return value in the parent is the child PID. In the child it is 0.
|
||||
func Fork() (pid uintptr, e error) {
|
||||
|
||||
pi := &RTL_USER_PROCESS_INFORMATION{}
|
||||
|
||||
ret := RtlCloneUserProcess(
|
||||
RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED|RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES,
|
||||
nil,
|
||||
nil,
|
||||
HANDLE(0),
|
||||
pi,
|
||||
)
|
||||
|
||||
switch ret {
|
||||
case RTL_CLONE_PARENT:
|
||||
pid = pi.ClientId.UniqueProcess
|
||||
ht, err := OpenThread(THREAD_ALL_ACCESS, false, pi.ClientId.UniqueThread)
|
||||
if err != nil {
|
||||
e = fmt.Errorf("OpenThread: %s", err)
|
||||
}
|
||||
err = ResumeThread(ht)
|
||||
if err != nil {
|
||||
e = fmt.Errorf("ResumeThread: %s", err)
|
||||
}
|
||||
CloseHandle(ht)
|
||||
case RTL_CLONE_CHILD:
|
||||
pid = 0
|
||||
err := AllocConsole()
|
||||
if err != nil {
|
||||
e = fmt.Errorf("AllocConsole: %s", err)
|
||||
}
|
||||
default:
|
||||
e = fmt.Errorf("0x%x", ret)
|
||||
}
|
||||
return
|
||||
}
|
||||
26
vendor/github.com/apenwarr/w32/fork_constants.go
generated
vendored
Normal file
26
vendor/github.com/apenwarr/w32/fork_constants.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package w32
|
||||
|
||||
const (
|
||||
RTL_CLONE_PROCESS_FLAGS_CREATE_SUSPENDED = 0x00000001
|
||||
RTL_CLONE_PROCESS_FLAGS_INHERIT_HANDLES = 0x00000002
|
||||
RTL_CLONE_PROCESS_FLAGS_NO_SYNCHRONIZE = 0x00000004
|
||||
|
||||
RTL_CLONE_PARENT = 0
|
||||
RTL_CLONE_CHILD = 297
|
||||
|
||||
THREAD_TERMINATE = 0x0001
|
||||
THREAD_SUSPEND_RESUME = 0x0002
|
||||
THREAD_GET_CONTEXT = 0x0008
|
||||
THREAD_SET_CONTEXT = 0x0010
|
||||
THREAD_SET_INFORMATION = 0x0020
|
||||
THREAD_QUERY_INFORMATION = 0x0040
|
||||
THREAD_SET_THREAD_TOKEN = 0x0080
|
||||
THREAD_IMPERSONATE = 0x0100
|
||||
THREAD_DIRECT_IMPERSONATION = 0x0200
|
||||
THREAD_SET_LIMITED_INFORMATION = 0x0400
|
||||
THREAD_QUERY_LIMITED_INFORMATION = 0x0800
|
||||
THREAD_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff
|
||||
|
||||
PROCESS_SET_SESSIONID = 0x0004
|
||||
PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff
|
||||
)
|
||||
89
vendor/github.com/apenwarr/w32/fork_typedef.go
generated
vendored
Normal file
89
vendor/github.com/apenwarr/w32/fork_typedef.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
package w32
|
||||
|
||||
// combase!_SECTION_IMAGE_INFORMATION
|
||||
// +0x000 TransferAddress : Ptr64 Void
|
||||
// +0x008 ZeroBits : Uint4B
|
||||
// +0x010 MaximumStackSize : Uint8B
|
||||
// +0x018 CommittedStackSize : Uint8B
|
||||
// +0x020 SubSystemType : Uint4B
|
||||
// +0x024 SubSystemMinorVersion : Uint2B
|
||||
// +0x026 SubSystemMajorVersion : Uint2B
|
||||
// +0x024 SubSystemVersion : Uint4B
|
||||
// +0x028 MajorOperatingSystemVersion : Uint2B
|
||||
// +0x02a MinorOperatingSystemVersion : Uint2B
|
||||
// +0x028 OperatingSystemVersion : Uint4B
|
||||
// +0x02c ImageCharacteristics : Uint2B
|
||||
// +0x02e DllCharacteristics : Uint2B
|
||||
// +0x030 Machine : Uint2B
|
||||
// +0x032 ImageContainsCode : UChar
|
||||
// +0x033 ImageFlags : UChar
|
||||
// +0x033 ComPlusNativeReady : Pos 0, 1 Bit
|
||||
// +0x033 ComPlusILOnly : Pos 1, 1 Bit
|
||||
// +0x033 ImageDynamicallyRelocated : Pos 2, 1 Bit
|
||||
// +0x033 ImageMappedFlat : Pos 3, 1 Bit
|
||||
// +0x033 BaseBelow4gb : Pos 4, 1 Bit
|
||||
// +0x033 ComPlusPrefer32bit : Pos 5, 1 Bit
|
||||
// +0x033 Reserved : Pos 6, 2 Bits
|
||||
// +0x034 LoaderFlags : Uint4B
|
||||
// +0x038 ImageFileSize : Uint4B
|
||||
// +0x03c CheckSum : Uint4B
|
||||
type SECTION_IMAGE_INFORMATION struct {
|
||||
TransferAddress uintptr
|
||||
ZeroBits uint32
|
||||
MaximumStackSize uint64
|
||||
CommittedStackSize uint64
|
||||
SubSystemType uint32
|
||||
SubSystemMinorVersion uint16
|
||||
SubSystemMajorVersion uint16
|
||||
SubSystemVersion uint32
|
||||
MajorOperatingSystemVersion uint16
|
||||
MinorOperatingSystemVersion uint16
|
||||
OperatingSystemVersion uint32
|
||||
ImageCharacteristics uint16
|
||||
DllCharacteristics uint16
|
||||
Machine uint16
|
||||
ImageContainsCode uint8
|
||||
ImageFlags uint8
|
||||
ComPlusFlags uint8
|
||||
LoaderFlags uint32
|
||||
ImageFileSize uint32
|
||||
CheckSum uint32
|
||||
}
|
||||
|
||||
func (si *SECTION_IMAGE_INFORMATION) ComPlusNativeReady() bool {
|
||||
return (si.ComPlusFlags & (1 << 0)) == 1
|
||||
}
|
||||
|
||||
func (si *SECTION_IMAGE_INFORMATION) ComPlusILOnly() bool {
|
||||
return (si.ComPlusFlags & (1 << 1)) == 1
|
||||
}
|
||||
|
||||
func (si *SECTION_IMAGE_INFORMATION) ImageDynamicallyRelocated() bool {
|
||||
return (si.ComPlusFlags & (1 << 2)) == 1
|
||||
}
|
||||
|
||||
func (si *SECTION_IMAGE_INFORMATION) ImageMappedFlat() bool {
|
||||
return (si.ComPlusFlags & (1 << 3)) == 1
|
||||
}
|
||||
|
||||
func (si *SECTION_IMAGE_INFORMATION) BaseBelow4gb() bool {
|
||||
return (si.ComPlusFlags & (1 << 4)) == 1
|
||||
}
|
||||
|
||||
func (si *SECTION_IMAGE_INFORMATION) ComPlusPrefer32bit() bool {
|
||||
return (si.ComPlusFlags & (1 << 5)) == 1
|
||||
}
|
||||
|
||||
// combase!_RTL_USER_PROCESS_INFORMATION
|
||||
// +0x000 Length : Uint4B
|
||||
// +0x008 Process : Ptr64 Void
|
||||
// +0x010 Thread : Ptr64 Void
|
||||
// +0x018 ClientId : _CLIENT_ID
|
||||
// +0x028 ImageInformation : _SECTION_IMAGE_INFORMATION
|
||||
type RTL_USER_PROCESS_INFORMATION struct {
|
||||
Length uint32
|
||||
Process HANDLE
|
||||
Thread HANDLE
|
||||
ClientId CLIENT_ID
|
||||
ImageInformation SECTION_IMAGE_INFORMATION
|
||||
}
|
||||
543
vendor/github.com/apenwarr/w32/gdi32.go
generated
vendored
Normal file
543
vendor/github.com/apenwarr/w32/gdi32.go
generated
vendored
Normal file
@@ -0,0 +1,543 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modgdi32 = syscall.NewLazyDLL("gdi32.dll")
|
||||
|
||||
procGetDeviceCaps = modgdi32.NewProc("GetDeviceCaps")
|
||||
procGetCurrentObject = modgdi32.NewProc("GetCurrentObject")
|
||||
procDeleteObject = modgdi32.NewProc("DeleteObject")
|
||||
procCreateFontIndirect = modgdi32.NewProc("CreateFontIndirectW")
|
||||
procAbortDoc = modgdi32.NewProc("AbortDoc")
|
||||
procBitBlt = modgdi32.NewProc("BitBlt")
|
||||
procPatBlt = modgdi32.NewProc("PatBlt")
|
||||
procCloseEnhMetaFile = modgdi32.NewProc("CloseEnhMetaFile")
|
||||
procCopyEnhMetaFile = modgdi32.NewProc("CopyEnhMetaFileW")
|
||||
procCreateBrushIndirect = modgdi32.NewProc("CreateBrushIndirect")
|
||||
procCreateCompatibleDC = modgdi32.NewProc("CreateCompatibleDC")
|
||||
procCreateDC = modgdi32.NewProc("CreateDCW")
|
||||
procCreateCompatibleBitmap = modgdi32.NewProc("CreateCompatibleBitmap")
|
||||
procCreateDIBSection = modgdi32.NewProc("CreateDIBSection")
|
||||
procCreateEnhMetaFile = modgdi32.NewProc("CreateEnhMetaFileW")
|
||||
procCreateIC = modgdi32.NewProc("CreateICW")
|
||||
procDeleteDC = modgdi32.NewProc("DeleteDC")
|
||||
procDeleteEnhMetaFile = modgdi32.NewProc("DeleteEnhMetaFile")
|
||||
procEllipse = modgdi32.NewProc("Ellipse")
|
||||
procEndDoc = modgdi32.NewProc("EndDoc")
|
||||
procEndPage = modgdi32.NewProc("EndPage")
|
||||
procExtCreatePen = modgdi32.NewProc("ExtCreatePen")
|
||||
procGetEnhMetaFile = modgdi32.NewProc("GetEnhMetaFileW")
|
||||
procGetEnhMetaFileHeader = modgdi32.NewProc("GetEnhMetaFileHeader")
|
||||
procGetObject = modgdi32.NewProc("GetObjectW")
|
||||
procGetStockObject = modgdi32.NewProc("GetStockObject")
|
||||
procGetTextExtentExPoint = modgdi32.NewProc("GetTextExtentExPointW")
|
||||
procGetTextExtentPoint32 = modgdi32.NewProc("GetTextExtentPoint32W")
|
||||
procGetTextMetrics = modgdi32.NewProc("GetTextMetricsW")
|
||||
procLineTo = modgdi32.NewProc("LineTo")
|
||||
procMoveToEx = modgdi32.NewProc("MoveToEx")
|
||||
procPlayEnhMetaFile = modgdi32.NewProc("PlayEnhMetaFile")
|
||||
procRectangle = modgdi32.NewProc("Rectangle")
|
||||
procResetDC = modgdi32.NewProc("ResetDCW")
|
||||
procSelectObject = modgdi32.NewProc("SelectObject")
|
||||
procSetBkMode = modgdi32.NewProc("SetBkMode")
|
||||
procSetBrushOrgEx = modgdi32.NewProc("SetBrushOrgEx")
|
||||
procSetStretchBltMode = modgdi32.NewProc("SetStretchBltMode")
|
||||
procSetTextColor = modgdi32.NewProc("SetTextColor")
|
||||
procSetBkColor = modgdi32.NewProc("SetBkColor")
|
||||
procStartDoc = modgdi32.NewProc("StartDocW")
|
||||
procStartPage = modgdi32.NewProc("StartPage")
|
||||
procStretchBlt = modgdi32.NewProc("StretchBlt")
|
||||
procSetDIBitsToDevice = modgdi32.NewProc("SetDIBitsToDevice")
|
||||
procChoosePixelFormat = modgdi32.NewProc("ChoosePixelFormat")
|
||||
procDescribePixelFormat = modgdi32.NewProc("DescribePixelFormat")
|
||||
procGetEnhMetaFilePixelFormat = modgdi32.NewProc("GetEnhMetaFilePixelFormat")
|
||||
procGetPixelFormat = modgdi32.NewProc("GetPixelFormat")
|
||||
procSetPixelFormat = modgdi32.NewProc("SetPixelFormat")
|
||||
procSwapBuffers = modgdi32.NewProc("SwapBuffers")
|
||||
)
|
||||
|
||||
func GetDeviceCaps(hdc HDC, index int) int {
|
||||
ret, _, _ := procGetDeviceCaps.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(index))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func GetCurrentObject(hdc HDC, uObjectType uint32) HGDIOBJ {
|
||||
ret, _, _ := procGetCurrentObject.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(uObjectType))
|
||||
|
||||
return HGDIOBJ(ret)
|
||||
}
|
||||
|
||||
func DeleteObject(hObject HGDIOBJ) bool {
|
||||
ret, _, _ := procDeleteObject.Call(
|
||||
uintptr(hObject))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func CreateFontIndirect(logFont *LOGFONT) HFONT {
|
||||
ret, _, _ := procCreateFontIndirect.Call(
|
||||
uintptr(unsafe.Pointer(logFont)))
|
||||
|
||||
return HFONT(ret)
|
||||
}
|
||||
|
||||
func AbortDoc(hdc HDC) int {
|
||||
ret, _, _ := procAbortDoc.Call(
|
||||
uintptr(hdc))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func BitBlt(hdcDest HDC, nXDest, nYDest, nWidth, nHeight int, hdcSrc HDC, nXSrc, nYSrc int, dwRop uint) {
|
||||
ret, _, _ := procBitBlt.Call(
|
||||
uintptr(hdcDest),
|
||||
uintptr(nXDest),
|
||||
uintptr(nYDest),
|
||||
uintptr(nWidth),
|
||||
uintptr(nHeight),
|
||||
uintptr(hdcSrc),
|
||||
uintptr(nXSrc),
|
||||
uintptr(nYSrc),
|
||||
uintptr(dwRop))
|
||||
|
||||
if ret == 0 {
|
||||
panic("BitBlt failed")
|
||||
}
|
||||
}
|
||||
|
||||
func PatBlt(hdc HDC, nXLeft, nYLeft, nWidth, nHeight int, dwRop uint) {
|
||||
ret, _, _ := procPatBlt.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(nXLeft),
|
||||
uintptr(nYLeft),
|
||||
uintptr(nWidth),
|
||||
uintptr(nHeight),
|
||||
uintptr(dwRop))
|
||||
|
||||
if ret == 0 {
|
||||
panic("PatBlt failed")
|
||||
}
|
||||
}
|
||||
|
||||
func CloseEnhMetaFile(hdc HDC) HENHMETAFILE {
|
||||
ret, _, _ := procCloseEnhMetaFile.Call(
|
||||
uintptr(hdc))
|
||||
|
||||
return HENHMETAFILE(ret)
|
||||
}
|
||||
|
||||
func CopyEnhMetaFile(hemfSrc HENHMETAFILE, lpszFile *uint16) HENHMETAFILE {
|
||||
ret, _, _ := procCopyEnhMetaFile.Call(
|
||||
uintptr(hemfSrc),
|
||||
uintptr(unsafe.Pointer(lpszFile)))
|
||||
|
||||
return HENHMETAFILE(ret)
|
||||
}
|
||||
|
||||
func CreateBrushIndirect(lplb *LOGBRUSH) HBRUSH {
|
||||
ret, _, _ := procCreateBrushIndirect.Call(
|
||||
uintptr(unsafe.Pointer(lplb)))
|
||||
|
||||
return HBRUSH(ret)
|
||||
}
|
||||
|
||||
func CreateCompatibleDC(hdc HDC) HDC {
|
||||
ret, _, _ := procCreateCompatibleDC.Call(
|
||||
uintptr(hdc))
|
||||
|
||||
if ret == 0 {
|
||||
panic("Create compatible DC failed")
|
||||
}
|
||||
|
||||
return HDC(ret)
|
||||
}
|
||||
|
||||
func CreateDC(lpszDriver, lpszDevice, lpszOutput *uint16, lpInitData *DEVMODE) HDC {
|
||||
ret, _, _ := procCreateDC.Call(
|
||||
uintptr(unsafe.Pointer(lpszDriver)),
|
||||
uintptr(unsafe.Pointer(lpszDevice)),
|
||||
uintptr(unsafe.Pointer(lpszOutput)),
|
||||
uintptr(unsafe.Pointer(lpInitData)))
|
||||
|
||||
return HDC(ret)
|
||||
}
|
||||
|
||||
func CreateCompatibleBitmap(hdc HDC, width, height uint) HBITMAP {
|
||||
ret, _, _ := procCreateCompatibleBitmap.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(width),
|
||||
uintptr(height))
|
||||
|
||||
return HBITMAP(ret)
|
||||
}
|
||||
|
||||
func CreateDIBSection(hdc HDC, pbmi *BITMAPINFO, iUsage uint, ppvBits *unsafe.Pointer, hSection HANDLE, dwOffset uint) HBITMAP {
|
||||
ret, _, _ := procCreateDIBSection.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(unsafe.Pointer(pbmi)),
|
||||
uintptr(iUsage),
|
||||
uintptr(unsafe.Pointer(ppvBits)),
|
||||
uintptr(hSection),
|
||||
uintptr(dwOffset))
|
||||
|
||||
return HBITMAP(ret)
|
||||
}
|
||||
|
||||
func CreateEnhMetaFile(hdcRef HDC, lpFilename *uint16, lpRect *RECT, lpDescription *uint16) HDC {
|
||||
ret, _, _ := procCreateEnhMetaFile.Call(
|
||||
uintptr(hdcRef),
|
||||
uintptr(unsafe.Pointer(lpFilename)),
|
||||
uintptr(unsafe.Pointer(lpRect)),
|
||||
uintptr(unsafe.Pointer(lpDescription)))
|
||||
|
||||
return HDC(ret)
|
||||
}
|
||||
|
||||
func CreateIC(lpszDriver, lpszDevice, lpszOutput *uint16, lpdvmInit *DEVMODE) HDC {
|
||||
ret, _, _ := procCreateIC.Call(
|
||||
uintptr(unsafe.Pointer(lpszDriver)),
|
||||
uintptr(unsafe.Pointer(lpszDevice)),
|
||||
uintptr(unsafe.Pointer(lpszOutput)),
|
||||
uintptr(unsafe.Pointer(lpdvmInit)))
|
||||
|
||||
return HDC(ret)
|
||||
}
|
||||
|
||||
func DeleteDC(hdc HDC) bool {
|
||||
ret, _, _ := procDeleteDC.Call(
|
||||
uintptr(hdc))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func DeleteEnhMetaFile(hemf HENHMETAFILE) bool {
|
||||
ret, _, _ := procDeleteEnhMetaFile.Call(
|
||||
uintptr(hemf))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func Ellipse(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int) bool {
|
||||
ret, _, _ := procEllipse.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(nLeftRect),
|
||||
uintptr(nTopRect),
|
||||
uintptr(nRightRect),
|
||||
uintptr(nBottomRect))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func EndDoc(hdc HDC) int {
|
||||
ret, _, _ := procEndDoc.Call(
|
||||
uintptr(hdc))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func EndPage(hdc HDC) int {
|
||||
ret, _, _ := procEndPage.Call(
|
||||
uintptr(hdc))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func ExtCreatePen(dwPenStyle, dwWidth uint, lplb *LOGBRUSH, dwStyleCount uint, lpStyle *uint) HPEN {
|
||||
ret, _, _ := procExtCreatePen.Call(
|
||||
uintptr(dwPenStyle),
|
||||
uintptr(dwWidth),
|
||||
uintptr(unsafe.Pointer(lplb)),
|
||||
uintptr(dwStyleCount),
|
||||
uintptr(unsafe.Pointer(lpStyle)))
|
||||
|
||||
return HPEN(ret)
|
||||
}
|
||||
|
||||
func GetEnhMetaFile(lpszMetaFile *uint16) HENHMETAFILE {
|
||||
ret, _, _ := procGetEnhMetaFile.Call(
|
||||
uintptr(unsafe.Pointer(lpszMetaFile)))
|
||||
|
||||
return HENHMETAFILE(ret)
|
||||
}
|
||||
|
||||
func GetEnhMetaFileHeader(hemf HENHMETAFILE, cbBuffer uint, lpemh *ENHMETAHEADER) uint {
|
||||
ret, _, _ := procGetEnhMetaFileHeader.Call(
|
||||
uintptr(hemf),
|
||||
uintptr(cbBuffer),
|
||||
uintptr(unsafe.Pointer(lpemh)))
|
||||
|
||||
return uint(ret)
|
||||
}
|
||||
|
||||
func GetObject(hgdiobj HGDIOBJ, cbBuffer uintptr, lpvObject unsafe.Pointer) int {
|
||||
ret, _, _ := procGetObject.Call(
|
||||
uintptr(hgdiobj),
|
||||
uintptr(cbBuffer),
|
||||
uintptr(lpvObject))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func GetStockObject(fnObject int) HGDIOBJ {
|
||||
ret, _, _ := procGetStockObject.Call(
|
||||
uintptr(fnObject))
|
||||
|
||||
return HGDIOBJ(ret)
|
||||
}
|
||||
|
||||
func GetTextExtentExPoint(hdc HDC, lpszStr *uint16, cchString, nMaxExtent int, lpnFit, alpDx *int, lpSize *SIZE) bool {
|
||||
ret, _, _ := procGetTextExtentExPoint.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(unsafe.Pointer(lpszStr)),
|
||||
uintptr(cchString),
|
||||
uintptr(nMaxExtent),
|
||||
uintptr(unsafe.Pointer(lpnFit)),
|
||||
uintptr(unsafe.Pointer(alpDx)),
|
||||
uintptr(unsafe.Pointer(lpSize)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func GetTextExtentPoint32(hdc HDC, lpString *uint16, c int, lpSize *SIZE) bool {
|
||||
ret, _, _ := procGetTextExtentPoint32.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(unsafe.Pointer(lpString)),
|
||||
uintptr(c),
|
||||
uintptr(unsafe.Pointer(lpSize)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func GetTextMetrics(hdc HDC, lptm *TEXTMETRIC) bool {
|
||||
ret, _, _ := procGetTextMetrics.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(unsafe.Pointer(lptm)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func LineTo(hdc HDC, nXEnd, nYEnd int) bool {
|
||||
ret, _, _ := procLineTo.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(nXEnd),
|
||||
uintptr(nYEnd))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func MoveToEx(hdc HDC, x, y int, lpPoint *POINT) bool {
|
||||
ret, _, _ := procMoveToEx.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(x),
|
||||
uintptr(y),
|
||||
uintptr(unsafe.Pointer(lpPoint)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func PlayEnhMetaFile(hdc HDC, hemf HENHMETAFILE, lpRect *RECT) bool {
|
||||
ret, _, _ := procPlayEnhMetaFile.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(hemf),
|
||||
uintptr(unsafe.Pointer(lpRect)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func Rectangle(hdc HDC, nLeftRect, nTopRect, nRightRect, nBottomRect int) bool {
|
||||
ret, _, _ := procRectangle.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(nLeftRect),
|
||||
uintptr(nTopRect),
|
||||
uintptr(nRightRect),
|
||||
uintptr(nBottomRect))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func ResetDC(hdc HDC, lpInitData *DEVMODE) HDC {
|
||||
ret, _, _ := procResetDC.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(unsafe.Pointer(lpInitData)))
|
||||
|
||||
return HDC(ret)
|
||||
}
|
||||
|
||||
func SelectObject(hdc HDC, hgdiobj HGDIOBJ) HGDIOBJ {
|
||||
ret, _, _ := procSelectObject.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(hgdiobj))
|
||||
|
||||
if ret == 0 {
|
||||
panic("SelectObject failed")
|
||||
}
|
||||
|
||||
return HGDIOBJ(ret)
|
||||
}
|
||||
|
||||
func SetBkMode(hdc HDC, iBkMode int) int {
|
||||
ret, _, _ := procSetBkMode.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(iBkMode))
|
||||
|
||||
if ret == 0 {
|
||||
panic("SetBkMode failed")
|
||||
}
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func SetBrushOrgEx(hdc HDC, nXOrg, nYOrg int, lppt *POINT) bool {
|
||||
ret, _, _ := procSetBrushOrgEx.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(nXOrg),
|
||||
uintptr(nYOrg),
|
||||
uintptr(unsafe.Pointer(lppt)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func SetStretchBltMode(hdc HDC, iStretchMode int) int {
|
||||
ret, _, _ := procSetStretchBltMode.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(iStretchMode))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func SetTextColor(hdc HDC, crColor COLORREF) COLORREF {
|
||||
ret, _, _ := procSetTextColor.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(crColor))
|
||||
|
||||
if ret == CLR_INVALID {
|
||||
panic("SetTextColor failed")
|
||||
}
|
||||
|
||||
return COLORREF(ret)
|
||||
}
|
||||
|
||||
func SetBkColor(hdc HDC, crColor COLORREF) COLORREF {
|
||||
ret, _, _ := procSetBkColor.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(crColor))
|
||||
|
||||
if ret == CLR_INVALID {
|
||||
panic("SetBkColor failed")
|
||||
}
|
||||
|
||||
return COLORREF(ret)
|
||||
}
|
||||
|
||||
func StartDoc(hdc HDC, lpdi *DOCINFO) int {
|
||||
ret, _, _ := procStartDoc.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(unsafe.Pointer(lpdi)))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func StartPage(hdc HDC) int {
|
||||
ret, _, _ := procStartPage.Call(
|
||||
uintptr(hdc))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func StretchBlt(hdcDest HDC, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest int, hdcSrc HDC, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc int, dwRop uint) {
|
||||
ret, _, _ := procStretchBlt.Call(
|
||||
uintptr(hdcDest),
|
||||
uintptr(nXOriginDest),
|
||||
uintptr(nYOriginDest),
|
||||
uintptr(nWidthDest),
|
||||
uintptr(nHeightDest),
|
||||
uintptr(hdcSrc),
|
||||
uintptr(nXOriginSrc),
|
||||
uintptr(nYOriginSrc),
|
||||
uintptr(nWidthSrc),
|
||||
uintptr(nHeightSrc),
|
||||
uintptr(dwRop))
|
||||
|
||||
if ret == 0 {
|
||||
panic("StretchBlt failed")
|
||||
}
|
||||
}
|
||||
|
||||
func SetDIBitsToDevice(hdc HDC, xDest, yDest, dwWidth, dwHeight, xSrc, ySrc int, uStartScan, cScanLines uint, lpvBits []byte, lpbmi *BITMAPINFO, fuColorUse uint) int {
|
||||
ret, _, _ := procSetDIBitsToDevice.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(xDest),
|
||||
uintptr(yDest),
|
||||
uintptr(dwWidth),
|
||||
uintptr(dwHeight),
|
||||
uintptr(xSrc),
|
||||
uintptr(ySrc),
|
||||
uintptr(uStartScan),
|
||||
uintptr(cScanLines),
|
||||
uintptr(unsafe.Pointer(&lpvBits[0])),
|
||||
uintptr(unsafe.Pointer(lpbmi)),
|
||||
uintptr(fuColorUse))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func ChoosePixelFormat(hdc HDC, pfd *PIXELFORMATDESCRIPTOR) int {
|
||||
ret, _, _ := procChoosePixelFormat.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(unsafe.Pointer(pfd)),
|
||||
)
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func DescribePixelFormat(hdc HDC, iPixelFormat int, nBytes uint, pfd *PIXELFORMATDESCRIPTOR) int {
|
||||
ret, _, _ := procDescribePixelFormat.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(iPixelFormat),
|
||||
uintptr(nBytes),
|
||||
uintptr(unsafe.Pointer(pfd)),
|
||||
)
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func GetEnhMetaFilePixelFormat(hemf HENHMETAFILE, cbBuffer uint32, pfd *PIXELFORMATDESCRIPTOR) uint {
|
||||
ret, _, _ := procGetEnhMetaFilePixelFormat.Call(
|
||||
uintptr(hemf),
|
||||
uintptr(cbBuffer),
|
||||
uintptr(unsafe.Pointer(pfd)),
|
||||
)
|
||||
return uint(ret)
|
||||
}
|
||||
|
||||
func GetPixelFormat(hdc HDC) int {
|
||||
ret, _, _ := procGetPixelFormat.Call(
|
||||
uintptr(hdc),
|
||||
)
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func SetPixelFormat(hdc HDC, iPixelFormat int, pfd *PIXELFORMATDESCRIPTOR) bool {
|
||||
ret, _, _ := procSetPixelFormat.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(iPixelFormat),
|
||||
uintptr(unsafe.Pointer(pfd)),
|
||||
)
|
||||
return ret == TRUE
|
||||
}
|
||||
|
||||
func SwapBuffers(hdc HDC) bool {
|
||||
ret, _, _ := procSwapBuffers.Call(uintptr(hdc))
|
||||
return ret == TRUE
|
||||
}
|
||||
175
vendor/github.com/apenwarr/w32/gdiplus.go
generated
vendored
Normal file
175
vendor/github.com/apenwarr/w32/gdiplus.go
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
Ok = 0
|
||||
GenericError = 1
|
||||
InvalidParameter = 2
|
||||
OutOfMemory = 3
|
||||
ObjectBusy = 4
|
||||
InsufficientBuffer = 5
|
||||
NotImplemented = 6
|
||||
Win32Error = 7
|
||||
WrongState = 8
|
||||
Aborted = 9
|
||||
FileNotFound = 10
|
||||
ValueOverflow = 11
|
||||
AccessDenied = 12
|
||||
UnknownImageFormat = 13
|
||||
FontFamilyNotFound = 14
|
||||
FontStyleNotFound = 15
|
||||
NotTrueTypeFont = 16
|
||||
UnsupportedGdiplusVersion = 17
|
||||
GdiplusNotInitialized = 18
|
||||
PropertyNotFound = 19
|
||||
PropertyNotSupported = 20
|
||||
ProfileNotFound = 21
|
||||
)
|
||||
|
||||
func GetGpStatus(s int32) string {
|
||||
switch s {
|
||||
case Ok:
|
||||
return "Ok"
|
||||
case GenericError:
|
||||
return "GenericError"
|
||||
case InvalidParameter:
|
||||
return "InvalidParameter"
|
||||
case OutOfMemory:
|
||||
return "OutOfMemory"
|
||||
case ObjectBusy:
|
||||
return "ObjectBusy"
|
||||
case InsufficientBuffer:
|
||||
return "InsufficientBuffer"
|
||||
case NotImplemented:
|
||||
return "NotImplemented"
|
||||
case Win32Error:
|
||||
return "Win32Error"
|
||||
case WrongState:
|
||||
return "WrongState"
|
||||
case Aborted:
|
||||
return "Aborted"
|
||||
case FileNotFound:
|
||||
return "FileNotFound"
|
||||
case ValueOverflow:
|
||||
return "ValueOverflow"
|
||||
case AccessDenied:
|
||||
return "AccessDenied"
|
||||
case UnknownImageFormat:
|
||||
return "UnknownImageFormat"
|
||||
case FontFamilyNotFound:
|
||||
return "FontFamilyNotFound"
|
||||
case FontStyleNotFound:
|
||||
return "FontStyleNotFound"
|
||||
case NotTrueTypeFont:
|
||||
return "NotTrueTypeFont"
|
||||
case UnsupportedGdiplusVersion:
|
||||
return "UnsupportedGdiplusVersion"
|
||||
case GdiplusNotInitialized:
|
||||
return "GdiplusNotInitialized"
|
||||
case PropertyNotFound:
|
||||
return "PropertyNotFound"
|
||||
case PropertyNotSupported:
|
||||
return "PropertyNotSupported"
|
||||
case ProfileNotFound:
|
||||
return "ProfileNotFound"
|
||||
}
|
||||
return "Unknown Status Value"
|
||||
}
|
||||
|
||||
var (
|
||||
token uintptr
|
||||
|
||||
modgdiplus = syscall.NewLazyDLL("gdiplus.dll")
|
||||
|
||||
procGdipCreateBitmapFromFile = modgdiplus.NewProc("GdipCreateBitmapFromFile")
|
||||
procGdipCreateBitmapFromHBITMAP = modgdiplus.NewProc("GdipCreateBitmapFromHBITMAP")
|
||||
procGdipCreateHBITMAPFromBitmap = modgdiplus.NewProc("GdipCreateHBITMAPFromBitmap")
|
||||
procGdipCreateBitmapFromResource = modgdiplus.NewProc("GdipCreateBitmapFromResource")
|
||||
procGdipCreateBitmapFromStream = modgdiplus.NewProc("GdipCreateBitmapFromStream")
|
||||
procGdipDisposeImage = modgdiplus.NewProc("GdipDisposeImage")
|
||||
procGdiplusShutdown = modgdiplus.NewProc("GdiplusShutdown")
|
||||
procGdiplusStartup = modgdiplus.NewProc("GdiplusStartup")
|
||||
)
|
||||
|
||||
func GdipCreateBitmapFromFile(filename string) (*uintptr, error) {
|
||||
var bitmap *uintptr
|
||||
ret, _, _ := procGdipCreateBitmapFromFile.Call(
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(filename))),
|
||||
uintptr(unsafe.Pointer(&bitmap)))
|
||||
|
||||
if ret != Ok {
|
||||
return nil, errors.New(fmt.Sprintf("GdipCreateBitmapFromFile failed with status '%s' for file '%s'", GetGpStatus(int32(ret)), filename))
|
||||
}
|
||||
|
||||
return bitmap, nil
|
||||
}
|
||||
|
||||
func GdipCreateBitmapFromResource(instance HINSTANCE, resId *uint16) (*uintptr, error) {
|
||||
var bitmap *uintptr
|
||||
ret, _, _ := procGdipCreateBitmapFromResource.Call(
|
||||
uintptr(instance),
|
||||
uintptr(unsafe.Pointer(resId)),
|
||||
uintptr(unsafe.Pointer(&bitmap)))
|
||||
|
||||
if ret != Ok {
|
||||
return nil, errors.New(fmt.Sprintf("GdiCreateBitmapFromResource failed with status '%s'", GetGpStatus(int32(ret))))
|
||||
}
|
||||
|
||||
return bitmap, nil
|
||||
}
|
||||
|
||||
func GdipCreateBitmapFromStream(stream *IStream) (*uintptr, error) {
|
||||
var bitmap *uintptr
|
||||
ret, _, _ := procGdipCreateBitmapFromStream.Call(
|
||||
uintptr(unsafe.Pointer(stream)),
|
||||
uintptr(unsafe.Pointer(&bitmap)))
|
||||
|
||||
if ret != Ok {
|
||||
return nil, errors.New(fmt.Sprintf("GdipCreateBitmapFromStream failed with status '%s'", GetGpStatus(int32(ret))))
|
||||
}
|
||||
|
||||
return bitmap, nil
|
||||
}
|
||||
|
||||
func GdipCreateHBITMAPFromBitmap(bitmap *uintptr, background uint32) (HBITMAP, error) {
|
||||
var hbitmap HBITMAP
|
||||
ret, _, _ := procGdipCreateHBITMAPFromBitmap.Call(
|
||||
uintptr(unsafe.Pointer(bitmap)),
|
||||
uintptr(unsafe.Pointer(&hbitmap)),
|
||||
uintptr(background))
|
||||
|
||||
if ret != Ok {
|
||||
return 0, errors.New(fmt.Sprintf("GdipCreateHBITMAPFromBitmap failed with status '%s'", GetGpStatus(int32(ret))))
|
||||
}
|
||||
|
||||
return hbitmap, nil
|
||||
}
|
||||
|
||||
func GdipDisposeImage(image *uintptr) {
|
||||
procGdipDisposeImage.Call(uintptr(unsafe.Pointer(image)))
|
||||
}
|
||||
|
||||
func GdiplusShutdown() {
|
||||
procGdiplusShutdown.Call(token)
|
||||
}
|
||||
|
||||
func GdiplusStartup(input *GdiplusStartupInput, output *GdiplusStartupOutput) {
|
||||
ret, _, _ := procGdiplusStartup.Call(
|
||||
uintptr(unsafe.Pointer(&token)),
|
||||
uintptr(unsafe.Pointer(input)),
|
||||
uintptr(unsafe.Pointer(output)))
|
||||
|
||||
if ret != Ok {
|
||||
panic("GdiplusStartup failed with status " + GetGpStatus(int32(ret)))
|
||||
}
|
||||
}
|
||||
43
vendor/github.com/apenwarr/w32/idispatch.go
generated
vendored
Normal file
43
vendor/github.com/apenwarr/w32/idispatch.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type pIDispatchVtbl struct {
|
||||
pQueryInterface uintptr
|
||||
pAddRef uintptr
|
||||
pRelease uintptr
|
||||
pGetTypeInfoCount uintptr
|
||||
pGetTypeInfo uintptr
|
||||
pGetIDsOfNames uintptr
|
||||
pInvoke uintptr
|
||||
}
|
||||
|
||||
type IDispatch struct {
|
||||
lpVtbl *pIDispatchVtbl
|
||||
}
|
||||
|
||||
func (this *IDispatch) QueryInterface(id *GUID) *IDispatch {
|
||||
return ComQueryInterface((*IUnknown)(unsafe.Pointer(this)), id)
|
||||
}
|
||||
|
||||
func (this *IDispatch) AddRef() int32 {
|
||||
return ComAddRef((*IUnknown)(unsafe.Pointer(this)))
|
||||
}
|
||||
|
||||
func (this *IDispatch) Release() int32 {
|
||||
return ComRelease((*IUnknown)(unsafe.Pointer(this)))
|
||||
}
|
||||
|
||||
func (this *IDispatch) GetIDsOfName(names []string) []int32 {
|
||||
return ComGetIDsOfName(this, names)
|
||||
}
|
||||
|
||||
func (this *IDispatch) Invoke(dispid int32, dispatch int16, params ...interface{}) *VARIANT {
|
||||
return ComInvoke(this, dispid, dispatch, params...)
|
||||
}
|
||||
31
vendor/github.com/apenwarr/w32/istream.go
generated
vendored
Normal file
31
vendor/github.com/apenwarr/w32/istream.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type pIStreamVtbl struct {
|
||||
pQueryInterface uintptr
|
||||
pAddRef uintptr
|
||||
pRelease uintptr
|
||||
}
|
||||
|
||||
type IStream struct {
|
||||
lpVtbl *pIStreamVtbl
|
||||
}
|
||||
|
||||
func (this *IStream) QueryInterface(id *GUID) *IDispatch {
|
||||
return ComQueryInterface((*IUnknown)(unsafe.Pointer(this)), id)
|
||||
}
|
||||
|
||||
func (this *IStream) AddRef() int32 {
|
||||
return ComAddRef((*IUnknown)(unsafe.Pointer(this)))
|
||||
}
|
||||
|
||||
func (this *IStream) Release() int32 {
|
||||
return ComRelease((*IUnknown)(unsafe.Pointer(this)))
|
||||
}
|
||||
27
vendor/github.com/apenwarr/w32/iunknown.go
generated
vendored
Normal file
27
vendor/github.com/apenwarr/w32/iunknown.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
type pIUnknownVtbl struct {
|
||||
pQueryInterface uintptr
|
||||
pAddRef uintptr
|
||||
pRelease uintptr
|
||||
}
|
||||
|
||||
type IUnknown struct {
|
||||
lpVtbl *pIUnknownVtbl
|
||||
}
|
||||
|
||||
func (this *IUnknown) QueryInterface(id *GUID) *IDispatch {
|
||||
return ComQueryInterface(this, id)
|
||||
}
|
||||
|
||||
func (this *IUnknown) AddRef() int32 {
|
||||
return ComAddRef(this)
|
||||
}
|
||||
|
||||
func (this *IUnknown) Release() int32 {
|
||||
return ComRelease(this)
|
||||
}
|
||||
388
vendor/github.com/apenwarr/w32/kernel32.go
generated
vendored
Normal file
388
vendor/github.com/apenwarr/w32/kernel32.go
generated
vendored
Normal file
@@ -0,0 +1,388 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
procGetModuleHandle = modkernel32.NewProc("GetModuleHandleW")
|
||||
procMulDiv = modkernel32.NewProc("MulDiv")
|
||||
procGetConsoleWindow = modkernel32.NewProc("GetConsoleWindow")
|
||||
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
|
||||
procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives")
|
||||
procGetUserDefaultLCID = modkernel32.NewProc("GetUserDefaultLCID")
|
||||
procLstrlen = modkernel32.NewProc("lstrlenW")
|
||||
procLstrcpy = modkernel32.NewProc("lstrcpyW")
|
||||
procGlobalAlloc = modkernel32.NewProc("GlobalAlloc")
|
||||
procGlobalFree = modkernel32.NewProc("GlobalFree")
|
||||
procGlobalLock = modkernel32.NewProc("GlobalLock")
|
||||
procGlobalUnlock = modkernel32.NewProc("GlobalUnlock")
|
||||
procMoveMemory = modkernel32.NewProc("RtlMoveMemory")
|
||||
procFindResource = modkernel32.NewProc("FindResourceW")
|
||||
procSizeofResource = modkernel32.NewProc("SizeofResource")
|
||||
procLockResource = modkernel32.NewProc("LockResource")
|
||||
procLoadResource = modkernel32.NewProc("LoadResource")
|
||||
procGetLastError = modkernel32.NewProc("GetLastError")
|
||||
// procOpenProcess = modkernel32.NewProc("OpenProcess")
|
||||
// procTerminateProcess = modkernel32.NewProc("TerminateProcess")
|
||||
procCloseHandle = modkernel32.NewProc("CloseHandle")
|
||||
procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot")
|
||||
procModule32First = modkernel32.NewProc("Module32FirstW")
|
||||
procModule32Next = modkernel32.NewProc("Module32NextW")
|
||||
procGetSystemTimes = modkernel32.NewProc("GetSystemTimes")
|
||||
procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo")
|
||||
procSetConsoleTextAttribute = modkernel32.NewProc("SetConsoleTextAttribute")
|
||||
procGetDiskFreeSpaceEx = modkernel32.NewProc("GetDiskFreeSpaceExW")
|
||||
procGetProcessTimes = modkernel32.NewProc("GetProcessTimes")
|
||||
procSetSystemTime = modkernel32.NewProc("SetSystemTime")
|
||||
procGetSystemTime = modkernel32.NewProc("GetSystemTime")
|
||||
procVirtualAllocEx = modkernel32.NewProc("VirtualAllocEx")
|
||||
procVirtualFreeEx = modkernel32.NewProc("VirtualFreeEx")
|
||||
procWriteProcessMemory = modkernel32.NewProc("WriteProcessMemory")
|
||||
procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory")
|
||||
procQueryPerformanceCounter = modkernel32.NewProc("QueryPerformanceCounter")
|
||||
procQueryPerformanceFrequency = modkernel32.NewProc("QueryPerformanceFrequency")
|
||||
)
|
||||
|
||||
func GetModuleHandle(modulename string) HINSTANCE {
|
||||
var mn uintptr
|
||||
if modulename == "" {
|
||||
mn = 0
|
||||
} else {
|
||||
mn = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(modulename)))
|
||||
}
|
||||
ret, _, _ := procGetModuleHandle.Call(mn)
|
||||
return HINSTANCE(ret)
|
||||
}
|
||||
|
||||
func MulDiv(number, numerator, denominator int) int {
|
||||
ret, _, _ := procMulDiv.Call(
|
||||
uintptr(number),
|
||||
uintptr(numerator),
|
||||
uintptr(denominator))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func GetConsoleWindow() HWND {
|
||||
ret, _, _ := procGetConsoleWindow.Call()
|
||||
|
||||
return HWND(ret)
|
||||
}
|
||||
|
||||
func GetCurrentThread() HANDLE {
|
||||
ret, _, _ := procGetCurrentThread.Call()
|
||||
|
||||
return HANDLE(ret)
|
||||
}
|
||||
|
||||
func GetLogicalDrives() uint32 {
|
||||
ret, _, _ := procGetLogicalDrives.Call()
|
||||
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func GetUserDefaultLCID() uint32 {
|
||||
ret, _, _ := procGetUserDefaultLCID.Call()
|
||||
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func Lstrlen(lpString *uint16) int {
|
||||
ret, _, _ := procLstrlen.Call(uintptr(unsafe.Pointer(lpString)))
|
||||
|
||||
return int(ret)
|
||||
}
|
||||
|
||||
func Lstrcpy(buf []uint16, lpString *uint16) {
|
||||
procLstrcpy.Call(
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uintptr(unsafe.Pointer(lpString)))
|
||||
}
|
||||
|
||||
func GlobalAlloc(uFlags uint, dwBytes uint32) HGLOBAL {
|
||||
ret, _, _ := procGlobalAlloc.Call(
|
||||
uintptr(uFlags),
|
||||
uintptr(dwBytes))
|
||||
|
||||
if ret == 0 {
|
||||
panic("GlobalAlloc failed")
|
||||
}
|
||||
|
||||
return HGLOBAL(ret)
|
||||
}
|
||||
|
||||
func GlobalFree(hMem HGLOBAL) {
|
||||
ret, _, _ := procGlobalFree.Call(uintptr(hMem))
|
||||
|
||||
if ret != 0 {
|
||||
panic("GlobalFree failed")
|
||||
}
|
||||
}
|
||||
|
||||
func GlobalLock(hMem HGLOBAL) unsafe.Pointer {
|
||||
ret, _, _ := procGlobalLock.Call(uintptr(hMem))
|
||||
|
||||
if ret == 0 {
|
||||
panic("GlobalLock failed")
|
||||
}
|
||||
|
||||
return unsafe.Pointer(ret)
|
||||
}
|
||||
|
||||
func GlobalUnlock(hMem HGLOBAL) bool {
|
||||
ret, _, _ := procGlobalUnlock.Call(uintptr(hMem))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func MoveMemory(destination, source unsafe.Pointer, length uint32) {
|
||||
procMoveMemory.Call(
|
||||
uintptr(unsafe.Pointer(destination)),
|
||||
uintptr(source),
|
||||
uintptr(length))
|
||||
}
|
||||
|
||||
func FindResource(hModule HMODULE, lpName, lpType *uint16) (HRSRC, error) {
|
||||
ret, _, _ := procFindResource.Call(
|
||||
uintptr(hModule),
|
||||
uintptr(unsafe.Pointer(lpName)),
|
||||
uintptr(unsafe.Pointer(lpType)))
|
||||
|
||||
if ret == 0 {
|
||||
return 0, syscall.GetLastError()
|
||||
}
|
||||
|
||||
return HRSRC(ret), nil
|
||||
}
|
||||
|
||||
func SizeofResource(hModule HMODULE, hResInfo HRSRC) uint32 {
|
||||
ret, _, _ := procSizeofResource.Call(
|
||||
uintptr(hModule),
|
||||
uintptr(hResInfo))
|
||||
|
||||
if ret == 0 {
|
||||
panic("SizeofResource failed")
|
||||
}
|
||||
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
func LockResource(hResData HGLOBAL) unsafe.Pointer {
|
||||
ret, _, _ := procLockResource.Call(uintptr(hResData))
|
||||
|
||||
if ret == 0 {
|
||||
panic("LockResource failed")
|
||||
}
|
||||
|
||||
return unsafe.Pointer(ret)
|
||||
}
|
||||
|
||||
func LoadResource(hModule HMODULE, hResInfo HRSRC) HGLOBAL {
|
||||
ret, _, _ := procLoadResource.Call(
|
||||
uintptr(hModule),
|
||||
uintptr(hResInfo))
|
||||
|
||||
if ret == 0 {
|
||||
panic("LoadResource failed")
|
||||
}
|
||||
|
||||
return HGLOBAL(ret)
|
||||
}
|
||||
|
||||
func GetLastError() uint32 {
|
||||
ret, _, _ := procGetLastError.Call()
|
||||
return uint32(ret)
|
||||
}
|
||||
|
||||
// func OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) HANDLE {
|
||||
// inherit := 0
|
||||
// if inheritHandle {
|
||||
// inherit = 1
|
||||
// }
|
||||
|
||||
// ret, _, _ := procOpenProcess.Call(
|
||||
// uintptr(desiredAccess),
|
||||
// uintptr(inherit),
|
||||
// uintptr(processId))
|
||||
// return HANDLE(ret)
|
||||
// }
|
||||
|
||||
// func TerminateProcess(hProcess HANDLE, uExitCode uint) bool {
|
||||
// ret, _, _ := procTerminateProcess.Call(
|
||||
// uintptr(hProcess),
|
||||
// uintptr(uExitCode))
|
||||
// return ret != 0
|
||||
// }
|
||||
|
||||
func CloseHandle(object HANDLE) bool {
|
||||
ret, _, _ := procCloseHandle.Call(
|
||||
uintptr(object))
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func CreateToolhelp32Snapshot(flags, processId uint32) HANDLE {
|
||||
ret, _, _ := procCreateToolhelp32Snapshot.Call(
|
||||
uintptr(flags),
|
||||
uintptr(processId))
|
||||
|
||||
if ret <= 0 {
|
||||
return HANDLE(0)
|
||||
}
|
||||
|
||||
return HANDLE(ret)
|
||||
}
|
||||
|
||||
func Module32First(snapshot HANDLE, me *MODULEENTRY32) bool {
|
||||
ret, _, _ := procModule32First.Call(
|
||||
uintptr(snapshot),
|
||||
uintptr(unsafe.Pointer(me)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func Module32Next(snapshot HANDLE, me *MODULEENTRY32) bool {
|
||||
ret, _, _ := procModule32Next.Call(
|
||||
uintptr(snapshot),
|
||||
uintptr(unsafe.Pointer(me)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func GetSystemTimes(lpIdleTime, lpKernelTime, lpUserTime *FILETIME) bool {
|
||||
ret, _, _ := procGetSystemTimes.Call(
|
||||
uintptr(unsafe.Pointer(lpIdleTime)),
|
||||
uintptr(unsafe.Pointer(lpKernelTime)),
|
||||
uintptr(unsafe.Pointer(lpUserTime)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func GetProcessTimes(hProcess HANDLE, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime *FILETIME) bool {
|
||||
ret, _, _ := procGetProcessTimes.Call(
|
||||
uintptr(hProcess),
|
||||
uintptr(unsafe.Pointer(lpCreationTime)),
|
||||
uintptr(unsafe.Pointer(lpExitTime)),
|
||||
uintptr(unsafe.Pointer(lpKernelTime)),
|
||||
uintptr(unsafe.Pointer(lpUserTime)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func GetConsoleScreenBufferInfo(hConsoleOutput HANDLE) *CONSOLE_SCREEN_BUFFER_INFO {
|
||||
var csbi CONSOLE_SCREEN_BUFFER_INFO
|
||||
ret, _, _ := procGetConsoleScreenBufferInfo.Call(
|
||||
uintptr(hConsoleOutput),
|
||||
uintptr(unsafe.Pointer(&csbi)))
|
||||
if ret == 0 {
|
||||
return nil
|
||||
}
|
||||
return &csbi
|
||||
}
|
||||
|
||||
func SetConsoleTextAttribute(hConsoleOutput HANDLE, wAttributes uint16) bool {
|
||||
ret, _, _ := procSetConsoleTextAttribute.Call(
|
||||
uintptr(hConsoleOutput),
|
||||
uintptr(wAttributes))
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func GetDiskFreeSpaceEx(dirName string) (r bool,
|
||||
freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes uint64) {
|
||||
ret, _, _ := procGetDiskFreeSpaceEx.Call(
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(dirName))),
|
||||
uintptr(unsafe.Pointer(&freeBytesAvailable)),
|
||||
uintptr(unsafe.Pointer(&totalNumberOfBytes)),
|
||||
uintptr(unsafe.Pointer(&totalNumberOfFreeBytes)))
|
||||
return ret != 0,
|
||||
freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes
|
||||
}
|
||||
|
||||
func GetSystemTime() *SYSTEMTIME {
|
||||
var time SYSTEMTIME
|
||||
procGetSystemTime.Call(
|
||||
uintptr(unsafe.Pointer(&time)))
|
||||
return &time
|
||||
}
|
||||
|
||||
func SetSystemTime(time *SYSTEMTIME) bool {
|
||||
ret, _, _ := procSetSystemTime.Call(
|
||||
uintptr(unsafe.Pointer(time)))
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func VirtualAllocEx(hProcess HANDLE, lpAddress, dwSize uintptr, flAllocationType, flProtect uint32) uintptr {
|
||||
ret, _, _ := procVirtualAllocEx.Call(
|
||||
uintptr(hProcess),
|
||||
lpAddress,
|
||||
dwSize,
|
||||
uintptr(flAllocationType),
|
||||
uintptr(flProtect),
|
||||
)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func VirtualFreeEx(hProcess HANDLE, lpAddress, dwSize uintptr, dwFreeType uint32) bool {
|
||||
ret, _, _ := procVirtualFreeEx.Call(
|
||||
uintptr(hProcess),
|
||||
lpAddress,
|
||||
dwSize,
|
||||
uintptr(dwFreeType),
|
||||
)
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func WriteProcessMemory(hProcess HANDLE, lpBaseAddress, lpBuffer, nSize uintptr) (int, bool) {
|
||||
var nBytesWritten int
|
||||
ret, _, _ := procWriteProcessMemory.Call(
|
||||
uintptr(hProcess),
|
||||
lpBaseAddress,
|
||||
lpBuffer,
|
||||
nSize,
|
||||
uintptr(unsafe.Pointer(&nBytesWritten)),
|
||||
)
|
||||
|
||||
return nBytesWritten, ret != 0
|
||||
}
|
||||
|
||||
func ReadProcessMemory(hProcess HANDLE, lpBaseAddress, nSize uintptr) (lpBuffer []uint16, lpNumberOfBytesRead int, ok bool) {
|
||||
|
||||
var nBytesRead int
|
||||
buf := make([]uint16, nSize)
|
||||
ret, _, _ := procReadProcessMemory.Call(
|
||||
uintptr(hProcess),
|
||||
lpBaseAddress,
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
nSize,
|
||||
uintptr(unsafe.Pointer(&nBytesRead)),
|
||||
)
|
||||
|
||||
return buf, nBytesRead, ret != 0
|
||||
}
|
||||
|
||||
func QueryPerformanceCounter() uint64 {
|
||||
result := uint64(0)
|
||||
procQueryPerformanceCounter.Call(
|
||||
uintptr(unsafe.Pointer(&result)),
|
||||
)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func QueryPerformanceFrequency() uint64 {
|
||||
result := uint64(0)
|
||||
procQueryPerformanceFrequency.Call(
|
||||
uintptr(unsafe.Pointer(&result)),
|
||||
)
|
||||
|
||||
return result
|
||||
}
|
||||
63
vendor/github.com/apenwarr/w32/ole32.go
generated
vendored
Normal file
63
vendor/github.com/apenwarr/w32/ole32.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modole32 = syscall.NewLazyDLL("ole32.dll")
|
||||
|
||||
procCoInitializeEx = modole32.NewProc("CoInitializeEx")
|
||||
procCoInitialize = modole32.NewProc("CoInitialize")
|
||||
procCoUninitialize = modole32.NewProc("CoUninitialize")
|
||||
procCreateStreamOnHGlobal = modole32.NewProc("CreateStreamOnHGlobal")
|
||||
)
|
||||
|
||||
func CoInitializeEx(coInit uintptr) HRESULT {
|
||||
ret, _, _ := procCoInitializeEx.Call(
|
||||
0,
|
||||
coInit)
|
||||
|
||||
switch uint32(ret) {
|
||||
case E_INVALIDARG:
|
||||
panic("CoInitializeEx failed with E_INVALIDARG")
|
||||
case E_OUTOFMEMORY:
|
||||
panic("CoInitializeEx failed with E_OUTOFMEMORY")
|
||||
case E_UNEXPECTED:
|
||||
panic("CoInitializeEx failed with E_UNEXPECTED")
|
||||
}
|
||||
|
||||
return HRESULT(ret)
|
||||
}
|
||||
|
||||
func CoInitialize() {
|
||||
procCoInitialize.Call(0)
|
||||
}
|
||||
|
||||
func CoUninitialize() {
|
||||
procCoUninitialize.Call()
|
||||
}
|
||||
|
||||
func CreateStreamOnHGlobal(hGlobal HGLOBAL, fDeleteOnRelease bool) *IStream {
|
||||
stream := new(IStream)
|
||||
ret, _, _ := procCreateStreamOnHGlobal.Call(
|
||||
uintptr(hGlobal),
|
||||
uintptr(BoolToBOOL(fDeleteOnRelease)),
|
||||
uintptr(unsafe.Pointer(&stream)))
|
||||
|
||||
switch uint32(ret) {
|
||||
case E_INVALIDARG:
|
||||
panic("CreateStreamOnHGlobal failed with E_INVALIDARG")
|
||||
case E_OUTOFMEMORY:
|
||||
panic("CreateStreamOnHGlobal failed with E_OUTOFMEMORY")
|
||||
case E_UNEXPECTED:
|
||||
panic("CreateStreamOnHGlobal failed with E_UNEXPECTED")
|
||||
}
|
||||
|
||||
return stream
|
||||
}
|
||||
48
vendor/github.com/apenwarr/w32/oleaut32.go
generated
vendored
Normal file
48
vendor/github.com/apenwarr/w32/oleaut32.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modoleaut32 = syscall.NewLazyDLL("oleaut32")
|
||||
|
||||
procVariantInit = modoleaut32.NewProc("VariantInit")
|
||||
procSysAllocString = modoleaut32.NewProc("SysAllocString")
|
||||
procSysFreeString = modoleaut32.NewProc("SysFreeString")
|
||||
procSysStringLen = modoleaut32.NewProc("SysStringLen")
|
||||
procCreateDispTypeInfo = modoleaut32.NewProc("CreateDispTypeInfo")
|
||||
procCreateStdDispatch = modoleaut32.NewProc("CreateStdDispatch")
|
||||
)
|
||||
|
||||
func VariantInit(v *VARIANT) {
|
||||
hr, _, _ := procVariantInit.Call(uintptr(unsafe.Pointer(v)))
|
||||
if hr != 0 {
|
||||
panic("Invoke VariantInit error.")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SysAllocString(v string) (ss *int16) {
|
||||
pss, _, _ := procSysAllocString.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(v))))
|
||||
ss = (*int16)(unsafe.Pointer(pss))
|
||||
return
|
||||
}
|
||||
|
||||
func SysFreeString(v *int16) {
|
||||
hr, _, _ := procSysFreeString.Call(uintptr(unsafe.Pointer(v)))
|
||||
if hr != 0 {
|
||||
panic("Invoke SysFreeString error.")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SysStringLen(v *int16) uint {
|
||||
l, _, _ := procSysStringLen.Call(uintptr(unsafe.Pointer(v)))
|
||||
return uint(l)
|
||||
}
|
||||
72
vendor/github.com/apenwarr/w32/opengl32.go
generated
vendored
Normal file
72
vendor/github.com/apenwarr/w32/opengl32.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modopengl32 = syscall.NewLazyDLL("opengl32.dll")
|
||||
|
||||
procwglCreateContext = modopengl32.NewProc("wglCreateContext")
|
||||
procwglCreateLayerContext = modopengl32.NewProc("wglCreateLayerContext")
|
||||
procwglDeleteContext = modopengl32.NewProc("wglDeleteContext")
|
||||
procwglGetProcAddress = modopengl32.NewProc("wglGetProcAddress")
|
||||
procwglMakeCurrent = modopengl32.NewProc("wglMakeCurrent")
|
||||
procwglShareLists = modopengl32.NewProc("wglShareLists")
|
||||
)
|
||||
|
||||
func WglCreateContext(hdc HDC) HGLRC {
|
||||
ret, _, _ := procwglCreateContext.Call(
|
||||
uintptr(hdc),
|
||||
)
|
||||
|
||||
return HGLRC(ret)
|
||||
}
|
||||
|
||||
func WglCreateLayerContext(hdc HDC, iLayerPlane int) HGLRC {
|
||||
ret, _, _ := procwglCreateLayerContext.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(iLayerPlane),
|
||||
)
|
||||
|
||||
return HGLRC(ret)
|
||||
}
|
||||
|
||||
func WglDeleteContext(hglrc HGLRC) bool {
|
||||
ret, _, _ := procwglDeleteContext.Call(
|
||||
uintptr(hglrc),
|
||||
)
|
||||
|
||||
return ret == TRUE
|
||||
}
|
||||
|
||||
func WglGetProcAddress(szProc string) uintptr {
|
||||
ret, _, _ := procwglGetProcAddress.Call(
|
||||
uintptr(unsafe.Pointer(syscall.StringBytePtr(szProc))),
|
||||
)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func WglMakeCurrent(hdc HDC, hglrc HGLRC) bool {
|
||||
ret, _, _ := procwglMakeCurrent.Call(
|
||||
uintptr(hdc),
|
||||
uintptr(hglrc),
|
||||
)
|
||||
|
||||
return ret == TRUE
|
||||
}
|
||||
|
||||
func WglShareLists(hglrc1, hglrc2 HGLRC) bool {
|
||||
ret, _, _ := procwglShareLists.Call(
|
||||
uintptr(hglrc1),
|
||||
uintptr(hglrc2),
|
||||
)
|
||||
|
||||
return ret == TRUE
|
||||
}
|
||||
25
vendor/github.com/apenwarr/w32/psapi.go
generated
vendored
Normal file
25
vendor/github.com/apenwarr/w32/psapi.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modpsapi = syscall.NewLazyDLL("psapi.dll")
|
||||
|
||||
procEnumProcesses = modpsapi.NewProc("EnumProcesses")
|
||||
)
|
||||
|
||||
func EnumProcesses(processIds []uint32, cb uint32, bytesReturned *uint32) bool {
|
||||
ret, _, _ := procEnumProcesses.Call(
|
||||
uintptr(unsafe.Pointer(&processIds[0])),
|
||||
uintptr(cb),
|
||||
uintptr(unsafe.Pointer(bytesReturned)))
|
||||
|
||||
return ret != 0
|
||||
}
|
||||
153
vendor/github.com/apenwarr/w32/shell32.go
generated
vendored
Normal file
153
vendor/github.com/apenwarr/w32/shell32.go
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
modshell32 = syscall.NewLazyDLL("shell32.dll")
|
||||
|
||||
procSHBrowseForFolder = modshell32.NewProc("SHBrowseForFolderW")
|
||||
procSHGetPathFromIDList = modshell32.NewProc("SHGetPathFromIDListW")
|
||||
procDragAcceptFiles = modshell32.NewProc("DragAcceptFiles")
|
||||
procDragQueryFile = modshell32.NewProc("DragQueryFileW")
|
||||
procDragQueryPoint = modshell32.NewProc("DragQueryPoint")
|
||||
procDragFinish = modshell32.NewProc("DragFinish")
|
||||
procShellExecute = modshell32.NewProc("ShellExecuteW")
|
||||
procExtractIcon = modshell32.NewProc("ExtractIconW")
|
||||
)
|
||||
|
||||
func SHBrowseForFolder(bi *BROWSEINFO) uintptr {
|
||||
ret, _, _ := procSHBrowseForFolder.Call(uintptr(unsafe.Pointer(bi)))
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func SHGetPathFromIDList(idl uintptr) string {
|
||||
buf := make([]uint16, 1024)
|
||||
procSHGetPathFromIDList.Call(
|
||||
idl,
|
||||
uintptr(unsafe.Pointer(&buf[0])))
|
||||
|
||||
return syscall.UTF16ToString(buf)
|
||||
}
|
||||
|
||||
func DragAcceptFiles(hwnd HWND, accept bool) {
|
||||
procDragAcceptFiles.Call(
|
||||
uintptr(hwnd),
|
||||
uintptr(BoolToBOOL(accept)))
|
||||
}
|
||||
|
||||
func DragQueryFile(hDrop HDROP, iFile uint) (fileName string, fileCount uint) {
|
||||
ret, _, _ := procDragQueryFile.Call(
|
||||
uintptr(hDrop),
|
||||
uintptr(iFile),
|
||||
0,
|
||||
0)
|
||||
|
||||
fileCount = uint(ret)
|
||||
|
||||
if iFile != 0xFFFFFFFF {
|
||||
buf := make([]uint16, fileCount+1)
|
||||
|
||||
ret, _, _ := procDragQueryFile.Call(
|
||||
uintptr(hDrop),
|
||||
uintptr(iFile),
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uintptr(fileCount+1))
|
||||
|
||||
if ret == 0 {
|
||||
panic("Invoke DragQueryFile error.")
|
||||
}
|
||||
|
||||
fileName = syscall.UTF16ToString(buf)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func DragQueryPoint(hDrop HDROP) (x, y int, isClientArea bool) {
|
||||
var pt POINT
|
||||
ret, _, _ := procDragQueryPoint.Call(
|
||||
uintptr(hDrop),
|
||||
uintptr(unsafe.Pointer(&pt)))
|
||||
|
||||
return int(pt.X), int(pt.Y), (ret == 1)
|
||||
}
|
||||
|
||||
func DragFinish(hDrop HDROP) {
|
||||
procDragFinish.Call(uintptr(hDrop))
|
||||
}
|
||||
|
||||
func ShellExecute(hwnd HWND, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
|
||||
var op, param, directory uintptr
|
||||
if len(lpOperation) != 0 {
|
||||
op = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation)))
|
||||
}
|
||||
if len(lpParameters) != 0 {
|
||||
param = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters)))
|
||||
}
|
||||
if len(lpDirectory) != 0 {
|
||||
directory = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory)))
|
||||
}
|
||||
|
||||
ret, _, _ := procShellExecute.Call(
|
||||
uintptr(hwnd),
|
||||
op,
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))),
|
||||
param,
|
||||
directory,
|
||||
uintptr(nShowCmd))
|
||||
|
||||
errorMsg := ""
|
||||
if ret != 0 && ret <= 32 {
|
||||
switch int(ret) {
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
errorMsg = "The specified file was not found."
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
errorMsg = "The specified path was not found."
|
||||
case ERROR_BAD_FORMAT:
|
||||
errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)."
|
||||
case SE_ERR_ACCESSDENIED:
|
||||
errorMsg = "The operating system denied access to the specified file."
|
||||
case SE_ERR_ASSOCINCOMPLETE:
|
||||
errorMsg = "The file name association is incomplete or invalid."
|
||||
case SE_ERR_DDEBUSY:
|
||||
errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed."
|
||||
case SE_ERR_DDEFAIL:
|
||||
errorMsg = "The DDE transaction failed."
|
||||
case SE_ERR_DDETIMEOUT:
|
||||
errorMsg = "The DDE transaction could not be completed because the request timed out."
|
||||
case SE_ERR_DLLNOTFOUND:
|
||||
errorMsg = "The specified DLL was not found."
|
||||
case SE_ERR_NOASSOC:
|
||||
errorMsg = "There is no application associated with the given file name extension. This error will also be returned if you attempt to print a file that is not printable."
|
||||
case SE_ERR_OOM:
|
||||
errorMsg = "There was not enough memory to complete the operation."
|
||||
case SE_ERR_SHARE:
|
||||
errorMsg = "A sharing violation occurred."
|
||||
default:
|
||||
errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", ret)
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New(errorMsg)
|
||||
}
|
||||
|
||||
func ExtractIcon(lpszExeFileName string, nIconIndex int) HICON {
|
||||
ret, _, _ := procExtractIcon.Call(
|
||||
0,
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpszExeFileName))),
|
||||
uintptr(nIconIndex))
|
||||
|
||||
return HICON(ret)
|
||||
}
|
||||
891
vendor/github.com/apenwarr/w32/typedef.go
generated
vendored
Normal file
891
vendor/github.com/apenwarr/w32/typedef.go
generated
vendored
Normal file
@@ -0,0 +1,891 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// From MSDN: Windows Data Types
|
||||
// http://msdn.microsoft.com/en-us/library/s3f49ktz.aspx
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751.aspx
|
||||
// ATOM WORD
|
||||
// BOOL int32
|
||||
// BOOLEAN byte
|
||||
// BYTE byte
|
||||
// CCHAR int8
|
||||
// CHAR int8
|
||||
// COLORREF DWORD
|
||||
// DWORD uint32
|
||||
// DWORDLONG ULONGLONG
|
||||
// DWORD_PTR ULONG_PTR
|
||||
// DWORD32 uint32
|
||||
// DWORD64 uint64
|
||||
// FLOAT float32
|
||||
// HACCEL HANDLE
|
||||
// HALF_PTR struct{} // ???
|
||||
// HANDLE PVOID
|
||||
// HBITMAP HANDLE
|
||||
// HBRUSH HANDLE
|
||||
// HCOLORSPACE HANDLE
|
||||
// HCONV HANDLE
|
||||
// HCONVLIST HANDLE
|
||||
// HCURSOR HANDLE
|
||||
// HDC HANDLE
|
||||
// HDDEDATA HANDLE
|
||||
// HDESK HANDLE
|
||||
// HDROP HANDLE
|
||||
// HDWP HANDLE
|
||||
// HENHMETAFILE HANDLE
|
||||
// HFILE HANDLE
|
||||
// HFONT HANDLE
|
||||
// HGDIOBJ HANDLE
|
||||
// HGLOBAL HANDLE
|
||||
// HHOOK HANDLE
|
||||
// HICON HANDLE
|
||||
// HINSTANCE HANDLE
|
||||
// HKEY HANDLE
|
||||
// HKL HANDLE
|
||||
// HLOCAL HANDLE
|
||||
// HMENU HANDLE
|
||||
// HMETAFILE HANDLE
|
||||
// HMODULE HANDLE
|
||||
// HPALETTE HANDLE
|
||||
// HPEN HANDLE
|
||||
// HRESULT int32
|
||||
// HRGN HANDLE
|
||||
// HSZ HANDLE
|
||||
// HWINSTA HANDLE
|
||||
// HWND HANDLE
|
||||
// INT int32
|
||||
// INT_PTR uintptr
|
||||
// INT8 int8
|
||||
// INT16 int16
|
||||
// INT32 int32
|
||||
// INT64 int64
|
||||
// LANGID WORD
|
||||
// LCID DWORD
|
||||
// LCTYPE DWORD
|
||||
// LGRPID DWORD
|
||||
// LONG int32
|
||||
// LONGLONG int64
|
||||
// LONG_PTR uintptr
|
||||
// LONG32 int32
|
||||
// LONG64 int64
|
||||
// LPARAM LONG_PTR
|
||||
// LPBOOL *BOOL
|
||||
// LPBYTE *BYTE
|
||||
// LPCOLORREF *COLORREF
|
||||
// LPCSTR *int8
|
||||
// LPCTSTR LPCWSTR
|
||||
// LPCVOID unsafe.Pointer
|
||||
// LPCWSTR *WCHAR
|
||||
// LPDWORD *DWORD
|
||||
// LPHANDLE *HANDLE
|
||||
// LPINT *INT
|
||||
// LPLONG *LONG
|
||||
// LPSTR *CHAR
|
||||
// LPTSTR LPWSTR
|
||||
// LPVOID unsafe.Pointer
|
||||
// LPWORD *WORD
|
||||
// LPWSTR *WCHAR
|
||||
// LRESULT LONG_PTR
|
||||
// PBOOL *BOOL
|
||||
// PBOOLEAN *BOOLEAN
|
||||
// PBYTE *BYTE
|
||||
// PCHAR *CHAR
|
||||
// PCSTR *CHAR
|
||||
// PCTSTR PCWSTR
|
||||
// PCWSTR *WCHAR
|
||||
// PDWORD *DWORD
|
||||
// PDWORDLONG *DWORDLONG
|
||||
// PDWORD_PTR *DWORD_PTR
|
||||
// PDWORD32 *DWORD32
|
||||
// PDWORD64 *DWORD64
|
||||
// PFLOAT *FLOAT
|
||||
// PHALF_PTR *HALF_PTR
|
||||
// PHANDLE *HANDLE
|
||||
// PHKEY *HKEY
|
||||
// PINT_PTR *INT_PTR
|
||||
// PINT8 *INT8
|
||||
// PINT16 *INT16
|
||||
// PINT32 *INT32
|
||||
// PINT64 *INT64
|
||||
// PLCID *LCID
|
||||
// PLONG *LONG
|
||||
// PLONGLONG *LONGLONG
|
||||
// PLONG_PTR *LONG_PTR
|
||||
// PLONG32 *LONG32
|
||||
// PLONG64 *LONG64
|
||||
// POINTER_32 struct{} // ???
|
||||
// POINTER_64 struct{} // ???
|
||||
// POINTER_SIGNED uintptr
|
||||
// POINTER_UNSIGNED uintptr
|
||||
// PSHORT *SHORT
|
||||
// PSIZE_T *SIZE_T
|
||||
// PSSIZE_T *SSIZE_T
|
||||
// PSTR *CHAR
|
||||
// PTBYTE *TBYTE
|
||||
// PTCHAR *TCHAR
|
||||
// PTSTR PWSTR
|
||||
// PUCHAR *UCHAR
|
||||
// PUHALF_PTR *UHALF_PTR
|
||||
// PUINT *UINT
|
||||
// PUINT_PTR *UINT_PTR
|
||||
// PUINT8 *UINT8
|
||||
// PUINT16 *UINT16
|
||||
// PUINT32 *UINT32
|
||||
// PUINT64 *UINT64
|
||||
// PULONG *ULONG
|
||||
// PULONGLONG *ULONGLONG
|
||||
// PULONG_PTR *ULONG_PTR
|
||||
// PULONG32 *ULONG32
|
||||
// PULONG64 *ULONG64
|
||||
// PUSHORT *USHORT
|
||||
// PVOID unsafe.Pointer
|
||||
// PWCHAR *WCHAR
|
||||
// PWORD *WORD
|
||||
// PWSTR *WCHAR
|
||||
// QWORD uint64
|
||||
// SC_HANDLE HANDLE
|
||||
// SC_LOCK LPVOID
|
||||
// SERVICE_STATUS_HANDLE HANDLE
|
||||
// SHORT int16
|
||||
// SIZE_T ULONG_PTR
|
||||
// SSIZE_T LONG_PTR
|
||||
// TBYTE WCHAR
|
||||
// TCHAR WCHAR
|
||||
// UCHAR uint8
|
||||
// UHALF_PTR struct{} // ???
|
||||
// UINT uint32
|
||||
// UINT_PTR uintptr
|
||||
// UINT8 uint8
|
||||
// UINT16 uint16
|
||||
// UINT32 uint32
|
||||
// UINT64 uint64
|
||||
// ULONG uint32
|
||||
// ULONGLONG uint64
|
||||
// ULONG_PTR uintptr
|
||||
// ULONG32 uint32
|
||||
// ULONG64 uint64
|
||||
// USHORT uint16
|
||||
// USN LONGLONG
|
||||
// WCHAR uint16
|
||||
// WORD uint16
|
||||
// WPARAM UINT_PTR
|
||||
type (
|
||||
ATOM uint16
|
||||
BOOL int32
|
||||
COLORREF uint32
|
||||
DWM_FRAME_COUNT uint64
|
||||
DWORD uint32
|
||||
HACCEL HANDLE
|
||||
HANDLE uintptr
|
||||
HBITMAP HANDLE
|
||||
HBRUSH HANDLE
|
||||
HCURSOR HANDLE
|
||||
HDC HANDLE
|
||||
HDROP HANDLE
|
||||
HDWP HANDLE
|
||||
HENHMETAFILE HANDLE
|
||||
HFONT HANDLE
|
||||
HGDIOBJ HANDLE
|
||||
HGLOBAL HANDLE
|
||||
HGLRC HANDLE
|
||||
HHOOK HANDLE
|
||||
HICON HANDLE
|
||||
HIMAGELIST HANDLE
|
||||
HINSTANCE HANDLE
|
||||
HKEY HANDLE
|
||||
HKL HANDLE
|
||||
HMENU HANDLE
|
||||
HMODULE HANDLE
|
||||
HMONITOR HANDLE
|
||||
HPEN HANDLE
|
||||
HRESULT int32
|
||||
HRGN HANDLE
|
||||
HRSRC HANDLE
|
||||
HTHUMBNAIL HANDLE
|
||||
HWND HANDLE
|
||||
LPARAM uintptr
|
||||
LPCVOID unsafe.Pointer
|
||||
LRESULT uintptr
|
||||
PVOID unsafe.Pointer
|
||||
QPC_TIME uint64
|
||||
ULONG_PTR uintptr
|
||||
WPARAM uintptr
|
||||
TRACEHANDLE uintptr
|
||||
)
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162805.aspx
|
||||
type POINT struct {
|
||||
X, Y int32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162897.aspx
|
||||
type RECT struct {
|
||||
Left, Top, Right, Bottom int32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms633577.aspx
|
||||
type WNDCLASSEX struct {
|
||||
Size uint32
|
||||
Style uint32
|
||||
WndProc uintptr
|
||||
ClsExtra int32
|
||||
WndExtra int32
|
||||
Instance HINSTANCE
|
||||
Icon HICON
|
||||
Cursor HCURSOR
|
||||
Background HBRUSH
|
||||
MenuName *uint16
|
||||
ClassName *uint16
|
||||
IconSm HICON
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644958.aspx
|
||||
type MSG struct {
|
||||
Hwnd HWND
|
||||
Message uint32
|
||||
WParam uintptr
|
||||
LParam uintptr
|
||||
Time uint32
|
||||
Pt POINT
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145037.aspx
|
||||
type LOGFONT struct {
|
||||
Height int32
|
||||
Width int32
|
||||
Escapement int32
|
||||
Orientation int32
|
||||
Weight int32
|
||||
Italic byte
|
||||
Underline byte
|
||||
StrikeOut byte
|
||||
CharSet byte
|
||||
OutPrecision byte
|
||||
ClipPrecision byte
|
||||
Quality byte
|
||||
PitchAndFamily byte
|
||||
FaceName [LF_FACESIZE]uint16
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646839.aspx
|
||||
type OPENFILENAME struct {
|
||||
StructSize uint32
|
||||
Owner HWND
|
||||
Instance HINSTANCE
|
||||
Filter *uint16
|
||||
CustomFilter *uint16
|
||||
MaxCustomFilter uint32
|
||||
FilterIndex uint32
|
||||
File *uint16
|
||||
MaxFile uint32
|
||||
FileTitle *uint16
|
||||
MaxFileTitle uint32
|
||||
InitialDir *uint16
|
||||
Title *uint16
|
||||
Flags uint32
|
||||
FileOffset uint16
|
||||
FileExtension uint16
|
||||
DefExt *uint16
|
||||
CustData uintptr
|
||||
FnHook uintptr
|
||||
TemplateName *uint16
|
||||
PvReserved unsafe.Pointer
|
||||
DwReserved uint32
|
||||
FlagsEx uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773205.aspx
|
||||
type BROWSEINFO struct {
|
||||
Owner HWND
|
||||
Root *uint16
|
||||
DisplayName *uint16
|
||||
Title *uint16
|
||||
Flags uint32
|
||||
CallbackFunc uintptr
|
||||
LParam uintptr
|
||||
Image int32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx
|
||||
type GUID struct {
|
||||
Data1 uint32
|
||||
Data2 uint16
|
||||
Data3 uint16
|
||||
Data4 [8]byte
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221627.aspx
|
||||
type VARIANT struct {
|
||||
VT uint16 // 2
|
||||
WReserved1 uint16 // 4
|
||||
WReserved2 uint16 // 6
|
||||
WReserved3 uint16 // 8
|
||||
Val int64 // 16
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221416.aspx
|
||||
type DISPPARAMS struct {
|
||||
Rgvarg uintptr
|
||||
RgdispidNamedArgs uintptr
|
||||
CArgs uint32
|
||||
CNamedArgs uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221133.aspx
|
||||
type EXCEPINFO struct {
|
||||
WCode uint16
|
||||
WReserved uint16
|
||||
BstrSource *uint16
|
||||
BstrDescription *uint16
|
||||
BstrHelpFile *uint16
|
||||
DwHelpContext uint32
|
||||
PvReserved uintptr
|
||||
PfnDeferredFillIn uintptr
|
||||
Scode int32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145035.aspx
|
||||
type LOGBRUSH struct {
|
||||
LbStyle uint32
|
||||
LbColor COLORREF
|
||||
LbHatch uintptr
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183565.aspx
|
||||
type DEVMODE struct {
|
||||
DmDeviceName [CCHDEVICENAME]uint16
|
||||
DmSpecVersion uint16
|
||||
DmDriverVersion uint16
|
||||
DmSize uint16
|
||||
DmDriverExtra uint16
|
||||
DmFields uint32
|
||||
DmOrientation int16
|
||||
DmPaperSize int16
|
||||
DmPaperLength int16
|
||||
DmPaperWidth int16
|
||||
DmScale int16
|
||||
DmCopies int16
|
||||
DmDefaultSource int16
|
||||
DmPrintQuality int16
|
||||
DmColor int16
|
||||
DmDuplex int16
|
||||
DmYResolution int16
|
||||
DmTTOption int16
|
||||
DmCollate int16
|
||||
DmFormName [CCHFORMNAME]uint16
|
||||
DmLogPixels uint16
|
||||
DmBitsPerPel uint32
|
||||
DmPelsWidth uint32
|
||||
DmPelsHeight uint32
|
||||
DmDisplayFlags uint32
|
||||
DmDisplayFrequency uint32
|
||||
DmICMMethod uint32
|
||||
DmICMIntent uint32
|
||||
DmMediaType uint32
|
||||
DmDitherType uint32
|
||||
DmReserved1 uint32
|
||||
DmReserved2 uint32
|
||||
DmPanningWidth uint32
|
||||
DmPanningHeight uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376.aspx
|
||||
type BITMAPINFOHEADER struct {
|
||||
BiSize uint32
|
||||
BiWidth int32
|
||||
BiHeight int32
|
||||
BiPlanes uint16
|
||||
BiBitCount uint16
|
||||
BiCompression uint32
|
||||
BiSizeImage uint32
|
||||
BiXPelsPerMeter int32
|
||||
BiYPelsPerMeter int32
|
||||
BiClrUsed uint32
|
||||
BiClrImportant uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162938.aspx
|
||||
type RGBQUAD struct {
|
||||
RgbBlue byte
|
||||
RgbGreen byte
|
||||
RgbRed byte
|
||||
RgbReserved byte
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183375.aspx
|
||||
type BITMAPINFO struct {
|
||||
BmiHeader BITMAPINFOHEADER
|
||||
BmiColors *RGBQUAD
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183371.aspx
|
||||
type BITMAP struct {
|
||||
BmType int32
|
||||
BmWidth int32
|
||||
BmHeight int32
|
||||
BmWidthBytes int32
|
||||
BmPlanes uint16
|
||||
BmBitsPixel uint16
|
||||
BmBits unsafe.Pointer
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183567.aspx
|
||||
type DIBSECTION struct {
|
||||
DsBm BITMAP
|
||||
DsBmih BITMAPINFOHEADER
|
||||
DsBitfields [3]uint32
|
||||
DshSection HANDLE
|
||||
DsOffset uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162607.aspx
|
||||
type ENHMETAHEADER struct {
|
||||
IType uint32
|
||||
NSize uint32
|
||||
RclBounds RECT
|
||||
RclFrame RECT
|
||||
DSignature uint32
|
||||
NVersion uint32
|
||||
NBytes uint32
|
||||
NRecords uint32
|
||||
NHandles uint16
|
||||
SReserved uint16
|
||||
NDescription uint32
|
||||
OffDescription uint32
|
||||
NPalEntries uint32
|
||||
SzlDevice SIZE
|
||||
SzlMillimeters SIZE
|
||||
CbPixelFormat uint32
|
||||
OffPixelFormat uint32
|
||||
BOpenGL uint32
|
||||
SzlMicrometers SIZE
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145106.aspx
|
||||
type SIZE struct {
|
||||
CX, CY int32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145132.aspx
|
||||
type TEXTMETRIC struct {
|
||||
TmHeight int32
|
||||
TmAscent int32
|
||||
TmDescent int32
|
||||
TmInternalLeading int32
|
||||
TmExternalLeading int32
|
||||
TmAveCharWidth int32
|
||||
TmMaxCharWidth int32
|
||||
TmWeight int32
|
||||
TmOverhang int32
|
||||
TmDigitizedAspectX int32
|
||||
TmDigitizedAspectY int32
|
||||
TmFirstChar uint16
|
||||
TmLastChar uint16
|
||||
TmDefaultChar uint16
|
||||
TmBreakChar uint16
|
||||
TmItalic byte
|
||||
TmUnderlined byte
|
||||
TmStruckOut byte
|
||||
TmPitchAndFamily byte
|
||||
TmCharSet byte
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd183574.aspx
|
||||
type DOCINFO struct {
|
||||
CbSize int32
|
||||
LpszDocName *uint16
|
||||
LpszOutput *uint16
|
||||
LpszDatatype *uint16
|
||||
FwType uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775514.aspx
|
||||
type NMHDR struct {
|
||||
HwndFrom HWND
|
||||
IdFrom uintptr
|
||||
Code uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774743.aspx
|
||||
type LVCOLUMN struct {
|
||||
Mask uint32
|
||||
Fmt int32
|
||||
Cx int32
|
||||
PszText *uint16
|
||||
CchTextMax int32
|
||||
ISubItem int32
|
||||
IImage int32
|
||||
IOrder int32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774760.aspx
|
||||
type LVITEM struct {
|
||||
Mask uint32
|
||||
IItem int32
|
||||
ISubItem int32
|
||||
State uint32
|
||||
StateMask uint32
|
||||
PszText *uint16
|
||||
CchTextMax int32
|
||||
IImage int32
|
||||
LParam uintptr
|
||||
IIndent int32
|
||||
IGroupId int32
|
||||
CColumns uint32
|
||||
PuColumns uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774754.aspx
|
||||
type LVHITTESTINFO struct {
|
||||
Pt POINT
|
||||
Flags uint32
|
||||
IItem int32
|
||||
ISubItem int32
|
||||
IGroup int32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774771.aspx
|
||||
type NMITEMACTIVATE struct {
|
||||
Hdr NMHDR
|
||||
IItem int32
|
||||
ISubItem int32
|
||||
UNewState uint32
|
||||
UOldState uint32
|
||||
UChanged uint32
|
||||
PtAction POINT
|
||||
LParam uintptr
|
||||
UKeyFlags uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774773.aspx
|
||||
type NMLISTVIEW struct {
|
||||
Hdr NMHDR
|
||||
IItem int32
|
||||
ISubItem int32
|
||||
UNewState uint32
|
||||
UOldState uint32
|
||||
UChanged uint32
|
||||
PtAction POINT
|
||||
LParam uintptr
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb774780.aspx
|
||||
type NMLVDISPINFO struct {
|
||||
Hdr NMHDR
|
||||
Item LVITEM
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb775507.aspx
|
||||
type INITCOMMONCONTROLSEX struct {
|
||||
DwSize uint32
|
||||
DwICC uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb760256.aspx
|
||||
type TOOLINFO struct {
|
||||
CbSize uint32
|
||||
UFlags uint32
|
||||
Hwnd HWND
|
||||
UId uintptr
|
||||
Rect RECT
|
||||
Hinst HINSTANCE
|
||||
LpszText *uint16
|
||||
LParam uintptr
|
||||
LpReserved unsafe.Pointer
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms645604.aspx
|
||||
type TRACKMOUSEEVENT struct {
|
||||
CbSize uint32
|
||||
DwFlags uint32
|
||||
HwndTrack HWND
|
||||
DwHoverTime uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms534067.aspx
|
||||
type GdiplusStartupInput struct {
|
||||
GdiplusVersion uint32
|
||||
DebugEventCallback uintptr
|
||||
SuppressBackgroundThread BOOL
|
||||
SuppressExternalCodecs BOOL
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms534068.aspx
|
||||
type GdiplusStartupOutput struct {
|
||||
NotificationHook uintptr
|
||||
NotificationUnhook uintptr
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162768.aspx
|
||||
type PAINTSTRUCT struct {
|
||||
Hdc HDC
|
||||
FErase BOOL
|
||||
RcPaint RECT
|
||||
FRestore BOOL
|
||||
FIncUpdate BOOL
|
||||
RgbReserved [32]byte
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms684225.aspx
|
||||
type MODULEENTRY32 struct {
|
||||
Size uint32
|
||||
ModuleID uint32
|
||||
ProcessID uint32
|
||||
GlblcntUsage uint32
|
||||
ProccntUsage uint32
|
||||
ModBaseAddr *uint8
|
||||
ModBaseSize uint32
|
||||
HModule HMODULE
|
||||
SzModule [MAX_MODULE_NAME32 + 1]uint16
|
||||
SzExePath [MAX_PATH]uint16
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx
|
||||
type FILETIME struct {
|
||||
DwLowDateTime uint32
|
||||
DwHighDateTime uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682119.aspx
|
||||
type COORD struct {
|
||||
X, Y int16
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms686311.aspx
|
||||
type SMALL_RECT struct {
|
||||
Left, Top, Right, Bottom int16
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093.aspx
|
||||
type CONSOLE_SCREEN_BUFFER_INFO struct {
|
||||
DwSize COORD
|
||||
DwCursorPosition COORD
|
||||
WAttributes uint16
|
||||
SrWindow SMALL_RECT
|
||||
DwMaximumWindowSize COORD
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb773244.aspx
|
||||
type MARGINS struct {
|
||||
CxLeftWidth, CxRightWidth, CyTopHeight, CyBottomHeight int32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969500.aspx
|
||||
type DWM_BLURBEHIND struct {
|
||||
DwFlags uint32
|
||||
fEnable BOOL
|
||||
hRgnBlur HRGN
|
||||
fTransitionOnMaximized BOOL
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969501.aspx
|
||||
type DWM_PRESENT_PARAMETERS struct {
|
||||
cbSize uint32
|
||||
fQueue BOOL
|
||||
cRefreshStart DWM_FRAME_COUNT
|
||||
cBuffer uint32
|
||||
fUseSourceRate BOOL
|
||||
rateSource UNSIGNED_RATIO
|
||||
cRefreshesPerFrame uint32
|
||||
eSampling DWM_SOURCE_FRAME_SAMPLING
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969502.aspx
|
||||
type DWM_THUMBNAIL_PROPERTIES struct {
|
||||
dwFlags uint32
|
||||
rcDestination RECT
|
||||
rcSource RECT
|
||||
opacity byte
|
||||
fVisible BOOL
|
||||
fSourceClientAreaOnly BOOL
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969503.aspx
|
||||
type DWM_TIMING_INFO struct {
|
||||
cbSize uint32
|
||||
rateRefresh UNSIGNED_RATIO
|
||||
qpcRefreshPeriod QPC_TIME
|
||||
rateCompose UNSIGNED_RATIO
|
||||
qpcVBlank QPC_TIME
|
||||
cRefresh DWM_FRAME_COUNT
|
||||
cDXRefresh uint32
|
||||
qpcCompose QPC_TIME
|
||||
cFrame DWM_FRAME_COUNT
|
||||
cDXPresent uint32
|
||||
cRefreshFrame DWM_FRAME_COUNT
|
||||
cFrameSubmitted DWM_FRAME_COUNT
|
||||
cDXPresentSubmitted uint32
|
||||
cFrameConfirmed DWM_FRAME_COUNT
|
||||
cDXPresentConfirmed uint32
|
||||
cRefreshConfirmed DWM_FRAME_COUNT
|
||||
cDXRefreshConfirmed uint32
|
||||
cFramesLate DWM_FRAME_COUNT
|
||||
cFramesOutstanding uint32
|
||||
cFrameDisplayed DWM_FRAME_COUNT
|
||||
qpcFrameDisplayed QPC_TIME
|
||||
cRefreshFrameDisplayed DWM_FRAME_COUNT
|
||||
cFrameComplete DWM_FRAME_COUNT
|
||||
qpcFrameComplete QPC_TIME
|
||||
cFramePending DWM_FRAME_COUNT
|
||||
qpcFramePending QPC_TIME
|
||||
cFramesDisplayed DWM_FRAME_COUNT
|
||||
cFramesComplete DWM_FRAME_COUNT
|
||||
cFramesPending DWM_FRAME_COUNT
|
||||
cFramesAvailable DWM_FRAME_COUNT
|
||||
cFramesDropped DWM_FRAME_COUNT
|
||||
cFramesMissed DWM_FRAME_COUNT
|
||||
cRefreshNextDisplayed DWM_FRAME_COUNT
|
||||
cRefreshNextPresented DWM_FRAME_COUNT
|
||||
cRefreshesDisplayed DWM_FRAME_COUNT
|
||||
cRefreshesPresented DWM_FRAME_COUNT
|
||||
cRefreshStarted DWM_FRAME_COUNT
|
||||
cPixelsReceived uint64
|
||||
cPixelsDrawn uint64
|
||||
cBuffersEmpty DWM_FRAME_COUNT
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd389402.aspx
|
||||
type MilMatrix3x2D struct {
|
||||
S_11, S_12, S_21, S_22 float64
|
||||
DX, DY float64
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa969505.aspx
|
||||
type UNSIGNED_RATIO struct {
|
||||
uiNumerator uint32
|
||||
uiDenominator uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms632603.aspx
|
||||
type CREATESTRUCT struct {
|
||||
CreateParams uintptr
|
||||
Instance HINSTANCE
|
||||
Menu HMENU
|
||||
Parent HWND
|
||||
Cy, Cx int32
|
||||
Y, X int32
|
||||
Style int32
|
||||
Name *uint16
|
||||
Class *uint16
|
||||
dwExStyle uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145065.aspx
|
||||
type MONITORINFO struct {
|
||||
CbSize uint32
|
||||
RcMonitor RECT
|
||||
RcWork RECT
|
||||
DwFlags uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145066.aspx
|
||||
type MONITORINFOEX struct {
|
||||
MONITORINFO
|
||||
SzDevice [CCHDEVICENAME]uint16
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd368826.aspx
|
||||
type PIXELFORMATDESCRIPTOR struct {
|
||||
Size uint16
|
||||
Version uint16
|
||||
DwFlags uint32
|
||||
IPixelType byte
|
||||
ColorBits byte
|
||||
RedBits, RedShift byte
|
||||
GreenBits, GreenShift byte
|
||||
BlueBits, BlueShift byte
|
||||
AlphaBits, AlphaShift byte
|
||||
AccumBits byte
|
||||
AccumRedBits byte
|
||||
AccumGreenBits byte
|
||||
AccumBlueBits byte
|
||||
AccumAlphaBits byte
|
||||
DepthBits, StencilBits byte
|
||||
AuxBuffers byte
|
||||
ILayerType byte
|
||||
Reserved byte
|
||||
DwLayerMask uint32
|
||||
DwVisibleMask uint32
|
||||
DwDamageMask uint32
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
|
||||
type INPUT struct {
|
||||
Type uint32
|
||||
Mi MOUSEINPUT
|
||||
Ki KEYBDINPUT
|
||||
Hi HARDWAREINPUT
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646273(v=vs.85).aspx
|
||||
type MOUSEINPUT struct {
|
||||
Dx int32
|
||||
Dy int32
|
||||
MouseData uint32
|
||||
DwFlags uint32
|
||||
Time uint32
|
||||
DwExtraInfo uintptr
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646271(v=vs.85).aspx
|
||||
type KEYBDINPUT struct {
|
||||
WVk uint16
|
||||
WScan uint16
|
||||
DwFlags uint32
|
||||
Time uint32
|
||||
DwExtraInfo uintptr
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646269(v=vs.85).aspx
|
||||
type HARDWAREINPUT struct {
|
||||
UMsg uint32
|
||||
WParamL uint16
|
||||
WParamH uint16
|
||||
}
|
||||
|
||||
type KbdInput struct {
|
||||
typ uint32
|
||||
ki KEYBDINPUT
|
||||
}
|
||||
|
||||
type MouseInput struct {
|
||||
typ uint32
|
||||
mi MOUSEINPUT
|
||||
}
|
||||
|
||||
type HardwareInput struct {
|
||||
typ uint32
|
||||
hi HARDWAREINPUT
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
|
||||
type SYSTEMTIME struct {
|
||||
Year uint16
|
||||
Month uint16
|
||||
DayOfWeek uint16
|
||||
Day uint16
|
||||
Hour uint16
|
||||
Minute uint16
|
||||
Second uint16
|
||||
Milliseconds uint16
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644967(v=vs.85).aspx
|
||||
type KBDLLHOOKSTRUCT struct {
|
||||
VkCode DWORD
|
||||
ScanCode DWORD
|
||||
Flags DWORD
|
||||
Time DWORD
|
||||
DwExtraInfo ULONG_PTR
|
||||
}
|
||||
|
||||
type HOOKPROC func(int, WPARAM, LPARAM) LRESULT
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms633498(v=vs.85).aspx
|
||||
type WNDENUMPROC func(HWND, LPARAM) LRESULT
|
||||
1046
vendor/github.com/apenwarr/w32/user32.go
generated
vendored
Normal file
1046
vendor/github.com/apenwarr/w32/user32.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
201
vendor/github.com/apenwarr/w32/utils.go
generated
vendored
Normal file
201
vendor/github.com/apenwarr/w32/utils.go
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func MakeIntResource(id uint16) *uint16 {
|
||||
return (*uint16)(unsafe.Pointer(uintptr(id)))
|
||||
}
|
||||
|
||||
func LOWORD(dw uint32) uint16 {
|
||||
return uint16(dw)
|
||||
}
|
||||
|
||||
func HIWORD(dw uint32) uint16 {
|
||||
return uint16(dw >> 16 & 0xffff)
|
||||
}
|
||||
|
||||
func BoolToBOOL(value bool) BOOL {
|
||||
if value {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func UTF16PtrToString(cstr *uint16) string {
|
||||
if cstr != nil {
|
||||
us := make([]uint16, 0, 256)
|
||||
for p := uintptr(unsafe.Pointer(cstr)); ; p += 2 {
|
||||
u := *(*uint16)(unsafe.Pointer(p))
|
||||
if u == 0 {
|
||||
return string(utf16.Decode(us))
|
||||
}
|
||||
us = append(us, u)
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func ComAddRef(unknown *IUnknown) int32 {
|
||||
ret, _, _ := syscall.Syscall(unknown.lpVtbl.pAddRef, 1,
|
||||
uintptr(unsafe.Pointer(unknown)),
|
||||
0,
|
||||
0)
|
||||
return int32(ret)
|
||||
}
|
||||
|
||||
func ComRelease(unknown *IUnknown) int32 {
|
||||
ret, _, _ := syscall.Syscall(unknown.lpVtbl.pRelease, 1,
|
||||
uintptr(unsafe.Pointer(unknown)),
|
||||
0,
|
||||
0)
|
||||
return int32(ret)
|
||||
}
|
||||
|
||||
func ComQueryInterface(unknown *IUnknown, id *GUID) *IDispatch {
|
||||
var disp *IDispatch
|
||||
hr, _, _ := syscall.Syscall(unknown.lpVtbl.pQueryInterface, 3,
|
||||
uintptr(unsafe.Pointer(unknown)),
|
||||
uintptr(unsafe.Pointer(id)),
|
||||
uintptr(unsafe.Pointer(&disp)))
|
||||
if hr != 0 {
|
||||
panic("Invoke QieryInterface error.")
|
||||
}
|
||||
return disp
|
||||
}
|
||||
|
||||
func ComGetIDsOfName(disp *IDispatch, names []string) []int32 {
|
||||
wnames := make([]*uint16, len(names))
|
||||
dispid := make([]int32, len(names))
|
||||
for i := 0; i < len(names); i++ {
|
||||
wnames[i] = syscall.StringToUTF16Ptr(names[i])
|
||||
}
|
||||
hr, _, _ := syscall.Syscall6(disp.lpVtbl.pGetIDsOfNames, 6,
|
||||
uintptr(unsafe.Pointer(disp)),
|
||||
uintptr(unsafe.Pointer(IID_NULL)),
|
||||
uintptr(unsafe.Pointer(&wnames[0])),
|
||||
uintptr(len(names)),
|
||||
uintptr(GetUserDefaultLCID()),
|
||||
uintptr(unsafe.Pointer(&dispid[0])))
|
||||
if hr != 0 {
|
||||
panic("Invoke GetIDsOfName error.")
|
||||
}
|
||||
return dispid
|
||||
}
|
||||
|
||||
func ComInvoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{}) (result *VARIANT) {
|
||||
var dispparams DISPPARAMS
|
||||
|
||||
if dispatch&DISPATCH_PROPERTYPUT != 0 {
|
||||
dispnames := [1]int32{DISPID_PROPERTYPUT}
|
||||
dispparams.RgdispidNamedArgs = uintptr(unsafe.Pointer(&dispnames[0]))
|
||||
dispparams.CNamedArgs = 1
|
||||
}
|
||||
var vargs []VARIANT
|
||||
if len(params) > 0 {
|
||||
vargs = make([]VARIANT, len(params))
|
||||
for i, v := range params {
|
||||
//n := len(params)-i-1
|
||||
n := len(params) - i - 1
|
||||
VariantInit(&vargs[n])
|
||||
switch v.(type) {
|
||||
case bool:
|
||||
if v.(bool) {
|
||||
vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0xffff}
|
||||
} else {
|
||||
vargs[n] = VARIANT{VT_BOOL, 0, 0, 0, 0}
|
||||
}
|
||||
case *bool:
|
||||
vargs[n] = VARIANT{VT_BOOL | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*bool))))}
|
||||
case byte:
|
||||
vargs[n] = VARIANT{VT_I1, 0, 0, 0, int64(v.(byte))}
|
||||
case *byte:
|
||||
vargs[n] = VARIANT{VT_I1 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*byte))))}
|
||||
case int16:
|
||||
vargs[n] = VARIANT{VT_I2, 0, 0, 0, int64(v.(int16))}
|
||||
case *int16:
|
||||
vargs[n] = VARIANT{VT_I2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int16))))}
|
||||
case uint16:
|
||||
vargs[n] = VARIANT{VT_UI2, 0, 0, 0, int64(v.(int16))}
|
||||
case *uint16:
|
||||
vargs[n] = VARIANT{VT_UI2 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint16))))}
|
||||
case int, int32:
|
||||
vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(int))}
|
||||
case *int, *int32:
|
||||
vargs[n] = VARIANT{VT_I4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int))))}
|
||||
case uint, uint32:
|
||||
vargs[n] = VARIANT{VT_UI4, 0, 0, 0, int64(v.(uint))}
|
||||
case *uint, *uint32:
|
||||
vargs[n] = VARIANT{VT_UI4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint))))}
|
||||
case int64:
|
||||
vargs[n] = VARIANT{VT_I8, 0, 0, 0, v.(int64)}
|
||||
case *int64:
|
||||
vargs[n] = VARIANT{VT_I8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*int64))))}
|
||||
case uint64:
|
||||
vargs[n] = VARIANT{VT_UI8, 0, 0, 0, int64(v.(uint64))}
|
||||
case *uint64:
|
||||
vargs[n] = VARIANT{VT_UI8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*uint64))))}
|
||||
case float32:
|
||||
vargs[n] = VARIANT{VT_R4, 0, 0, 0, int64(v.(float32))}
|
||||
case *float32:
|
||||
vargs[n] = VARIANT{VT_R4 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float32))))}
|
||||
case float64:
|
||||
vargs[n] = VARIANT{VT_R8, 0, 0, 0, int64(v.(float64))}
|
||||
case *float64:
|
||||
vargs[n] = VARIANT{VT_R8 | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*float64))))}
|
||||
case string:
|
||||
vargs[n] = VARIANT{VT_BSTR, 0, 0, 0, int64(uintptr(unsafe.Pointer(SysAllocString(v.(string)))))}
|
||||
case *string:
|
||||
vargs[n] = VARIANT{VT_BSTR | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*string))))}
|
||||
case *IDispatch:
|
||||
vargs[n] = VARIANT{VT_DISPATCH, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*IDispatch))))}
|
||||
case **IDispatch:
|
||||
vargs[n] = VARIANT{VT_DISPATCH | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(**IDispatch))))}
|
||||
case nil:
|
||||
vargs[n] = VARIANT{VT_NULL, 0, 0, 0, 0}
|
||||
case *VARIANT:
|
||||
vargs[n] = VARIANT{VT_VARIANT | VT_BYREF, 0, 0, 0, int64(uintptr(unsafe.Pointer(v.(*VARIANT))))}
|
||||
default:
|
||||
panic("unknown type")
|
||||
}
|
||||
}
|
||||
dispparams.Rgvarg = uintptr(unsafe.Pointer(&vargs[0]))
|
||||
dispparams.CArgs = uint32(len(params))
|
||||
}
|
||||
|
||||
var ret VARIANT
|
||||
var excepInfo EXCEPINFO
|
||||
VariantInit(&ret)
|
||||
hr, _, _ := syscall.Syscall9(disp.lpVtbl.pInvoke, 8,
|
||||
uintptr(unsafe.Pointer(disp)),
|
||||
uintptr(dispid),
|
||||
uintptr(unsafe.Pointer(IID_NULL)),
|
||||
uintptr(GetUserDefaultLCID()),
|
||||
uintptr(dispatch),
|
||||
uintptr(unsafe.Pointer(&dispparams)),
|
||||
uintptr(unsafe.Pointer(&ret)),
|
||||
uintptr(unsafe.Pointer(&excepInfo)),
|
||||
0)
|
||||
if hr != 0 {
|
||||
if excepInfo.BstrDescription != nil {
|
||||
bs := UTF16PtrToString(excepInfo.BstrDescription)
|
||||
panic(bs)
|
||||
}
|
||||
}
|
||||
for _, varg := range vargs {
|
||||
if varg.VT == VT_BSTR && varg.Val != 0 {
|
||||
SysFreeString(((*int16)(unsafe.Pointer(uintptr(varg.Val)))))
|
||||
}
|
||||
}
|
||||
result = &ret
|
||||
return
|
||||
}
|
||||
13
vendor/github.com/apenwarr/w32/vars.go
generated
vendored
Normal file
13
vendor/github.com/apenwarr/w32/vars.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2010-2012 The W32 Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package w32
|
||||
|
||||
var (
|
||||
IID_NULL = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}
|
||||
IID_IUnknown = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}
|
||||
IID_IDispatch = &GUID{0x00020400, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}
|
||||
IID_IConnectionPointContainer = &GUID{0xB196B284, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}
|
||||
IID_IConnectionPoint = &GUID{0xB196B286, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}
|
||||
)
|
||||
3
vendor/github.com/go-chi/chi/v5/.gitignore
generated
vendored
Normal file
3
vendor/github.com/go-chi/chi/v5/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.idea
|
||||
*.sw?
|
||||
.vscode
|
||||
279
vendor/github.com/go-chi/chi/v5/CHANGELOG.md
generated
vendored
Normal file
279
vendor/github.com/go-chi/chi/v5/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,279 @@
|
||||
# Changelog
|
||||
|
||||
## v5.0.0 (2021-02-27)
|
||||
|
||||
- chi v5, `github.com/go-chi/chi/v5` introduces the adoption of Go's SIV to adhere to the current state-of-the-tools in Go.
|
||||
- chi v1.5.x did not work out as planned, as the Go tooling is too powerful and chi's adoption is too wide.
|
||||
The most responsible thing to do for everyone's benefit is to just release v5 with SIV, so I present to you all,
|
||||
chi v5 at `github.com/go-chi/chi/v5`. I hope someday the developer experience and ergonomics I've been seeking
|
||||
will still come to fruition in some form, see https://github.com/golang/go/issues/44550
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v1.5.4...v5.0.0
|
||||
|
||||
|
||||
## v1.5.4 (2021-02-27)
|
||||
|
||||
- Undo prior retraction in v1.5.3 as we prepare for v5.0.0 release
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v1.5.3...v1.5.4
|
||||
|
||||
|
||||
## v1.5.3 (2021-02-21)
|
||||
|
||||
- Update go.mod to go 1.16 with new retract directive marking all versions without prior go.mod support
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v1.5.2...v1.5.3
|
||||
|
||||
|
||||
## v1.5.2 (2021-02-10)
|
||||
|
||||
- Reverting allocation optimization as a precaution as go test -race fails.
|
||||
- Minor improvements, see history below
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v1.5.1...v1.5.2
|
||||
|
||||
|
||||
## v1.5.1 (2020-12-06)
|
||||
|
||||
- Performance improvement: removing 1 allocation by foregoing context.WithValue, thank you @bouk for
|
||||
your contribution (https://github.com/go-chi/chi/pull/555). Note: new benchmarks posted in README.
|
||||
- `middleware.CleanPath`: new middleware that clean's request path of double slashes
|
||||
- deprecate & remove `chi.ServerBaseContext` in favour of stdlib `http.Server#BaseContext`
|
||||
- plus other tiny improvements, see full commit history below
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v4.1.2...v1.5.1
|
||||
|
||||
|
||||
## v1.5.0 (2020-11-12) - now with go.mod support
|
||||
|
||||
`chi` dates back to 2016 with it's original implementation as one of the first routers to adopt the newly introduced
|
||||
context.Context api to the stdlib -- set out to design a router that is faster, more modular and simpler than anything
|
||||
else out there -- while not introducing any custom handler types or dependencies. Today, `chi` still has zero dependencies,
|
||||
and in many ways is future proofed from changes, given it's minimal nature. Between versions, chi's iterations have been very
|
||||
incremental, with the architecture and api being the same today as it was originally designed in 2016. For this reason it
|
||||
makes chi a pretty easy project to maintain, as well thanks to the many amazing community contributions over the years
|
||||
to who all help make chi better (total of 86 contributors to date -- thanks all!).
|
||||
|
||||
Chi has been an labour of love, art and engineering, with the goals to offer beautiful ergonomics, flexibility, performance
|
||||
and simplicity when building HTTP services with Go. I've strived to keep the router very minimal in surface area / code size,
|
||||
and always improving the code wherever possible -- and as of today the `chi` package is just 1082 lines of code (not counting
|
||||
middlewares, which are all optional). As well, I don't have the exact metrics, but from my analysis and email exchanges from
|
||||
companies and developers, chi is used by thousands of projects around the world -- thank you all as there is no better form of
|
||||
joy for me than to have art I had started be helpful and enjoyed by others. And of course I use chi in all of my own projects too :)
|
||||
|
||||
For me, the asthetics of chi's code and usage are very important. With the introduction of Go's module support
|
||||
(which I'm a big fan of), chi's past versioning scheme choice to v2, v3 and v4 would mean I'd require the import path
|
||||
of "github.com/go-chi/chi/v4", leading to the lengthy discussion at https://github.com/go-chi/chi/issues/462.
|
||||
Haha, to some, you may be scratching your head why I've spent > 1 year stalling to adopt "/vXX" convention in the import
|
||||
path -- which isn't horrible in general -- but for chi, I'm unable to accept it as I strive for perfection in it's API design,
|
||||
aesthetics and simplicity. It just doesn't feel good to me given chi's simple nature -- I do not foresee a "v5" or "v6",
|
||||
and upgrading between versions in the future will also be just incremental.
|
||||
|
||||
I do understand versioning is a part of the API design as well, which is why the solution for a while has been to "do nothing",
|
||||
as Go supports both old and new import paths with/out go.mod. However, now that Go module support has had time to iron out kinks and
|
||||
is adopted everywhere, it's time for chi to get with the times. Luckily, I've discovered a path forward that will make me happy,
|
||||
while also not breaking anyone's app who adopted a prior versioning from tags in v2/v3/v4. I've made an experimental release of
|
||||
v1.5.0 with go.mod silently, and tested it with new and old projects, to ensure the developer experience is preserved, and it's
|
||||
largely unnoticed. Fortunately, Go's toolchain will check the tags of a repo and consider the "latest" tag the one with go.mod.
|
||||
However, you can still request a specific older tag such as v4.1.2, and everything will "just work". But new users can just
|
||||
`go get github.com/go-chi/chi` or `go get github.com/go-chi/chi@latest` and they will get the latest version which contains
|
||||
go.mod support, which is v1.5.0+. `chi` will not change very much over the years, just like it hasn't changed much from 4 years ago.
|
||||
Therefore, we will stay on v1.x from here on, starting from v1.5.0. Any breaking changes will bump a "minor" release and
|
||||
backwards-compatible improvements/fixes will bump a "tiny" release.
|
||||
|
||||
For existing projects who want to upgrade to the latest go.mod version, run: `go get -u github.com/go-chi/chi@v1.5.0`,
|
||||
which will get you on the go.mod version line (as Go's mod cache may still remember v4.x). Brand new systems can run
|
||||
`go get -u github.com/go-chi/chi` or `go get -u github.com/go-chi/chi@latest` to install chi, which will install v1.5.0+
|
||||
built with go.mod support.
|
||||
|
||||
My apologies to the developers who will disagree with the decisions above, but, hope you'll try it and see it's a very
|
||||
minor request which is backwards compatible and won't break your existing installations.
|
||||
|
||||
Cheers all, happy coding!
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## v4.1.2 (2020-06-02)
|
||||
|
||||
- fix that handles MethodNotAllowed with path variables, thank you @caseyhadden for your contribution
|
||||
- fix to replace nested wildcards correctly in RoutePattern, thank you @@unmultimedio for your contribution
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v4.1.1...v4.1.2
|
||||
|
||||
|
||||
## v4.1.1 (2020-04-16)
|
||||
|
||||
- fix for issue https://github.com/go-chi/chi/issues/411 which allows for overlapping regexp
|
||||
route to the correct handler through a recursive tree search, thanks to @Jahaja for the PR/fix!
|
||||
- new middleware.RouteHeaders as a simple router for request headers with wildcard support
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v4.1.0...v4.1.1
|
||||
|
||||
|
||||
## v4.1.0 (2020-04-1)
|
||||
|
||||
- middleware.LogEntry: Write method on interface now passes the response header
|
||||
and an extra interface type useful for custom logger implementations.
|
||||
- middleware.WrapResponseWriter: minor fix
|
||||
- middleware.Recoverer: a bit prettier
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v4.0.4...v4.1.0
|
||||
|
||||
## v4.0.4 (2020-03-24)
|
||||
|
||||
- middleware.Recoverer: new pretty stack trace printing (https://github.com/go-chi/chi/pull/496)
|
||||
- a few minor improvements and fixes
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v4.0.3...v4.0.4
|
||||
|
||||
|
||||
## v4.0.3 (2020-01-09)
|
||||
|
||||
- core: fix regexp routing to include default value when param is not matched
|
||||
- middleware: rewrite of middleware.Compress
|
||||
- middleware: suppress http.ErrAbortHandler in middleware.Recoverer
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v4.0.2...v4.0.3
|
||||
|
||||
|
||||
## v4.0.2 (2019-02-26)
|
||||
|
||||
- Minor fixes
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v4.0.1...v4.0.2
|
||||
|
||||
|
||||
## v4.0.1 (2019-01-21)
|
||||
|
||||
- Fixes issue with compress middleware: #382 #385
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v4.0.0...v4.0.1
|
||||
|
||||
|
||||
## v4.0.0 (2019-01-10)
|
||||
|
||||
- chi v4 requires Go 1.10.3+ (or Go 1.9.7+) - we have deprecated support for Go 1.7 and 1.8
|
||||
- router: respond with 404 on router with no routes (#362)
|
||||
- router: additional check to ensure wildcard is at the end of a url pattern (#333)
|
||||
- middleware: deprecate use of http.CloseNotifier (#347)
|
||||
- middleware: fix RedirectSlashes to include query params on redirect (#334)
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v3.3.4...v4.0.0
|
||||
|
||||
|
||||
## v3.3.4 (2019-01-07)
|
||||
|
||||
- Minor middleware improvements. No changes to core library/router. Moving v3 into its
|
||||
- own branch as a version of chi for Go 1.7, 1.8, 1.9, 1.10, 1.11
|
||||
- History of changes: see https://github.com/go-chi/chi/compare/v3.3.3...v3.3.4
|
||||
|
||||
|
||||
## v3.3.3 (2018-08-27)
|
||||
|
||||
- Minor release
|
||||
- See https://github.com/go-chi/chi/compare/v3.3.2...v3.3.3
|
||||
|
||||
|
||||
## v3.3.2 (2017-12-22)
|
||||
|
||||
- Support to route trailing slashes on mounted sub-routers (#281)
|
||||
- middleware: new `ContentCharset` to check matching charsets. Thank you
|
||||
@csucu for your community contribution!
|
||||
|
||||
|
||||
## v3.3.1 (2017-11-20)
|
||||
|
||||
- middleware: new `AllowContentType` handler for explicit whitelist of accepted request Content-Types
|
||||
- middleware: new `SetHeader` handler for short-hand middleware to set a response header key/value
|
||||
- Minor bug fixes
|
||||
|
||||
|
||||
## v3.3.0 (2017-10-10)
|
||||
|
||||
- New chi.RegisterMethod(method) to add support for custom HTTP methods, see _examples/custom-method for usage
|
||||
- Deprecated LINK and UNLINK methods from the default list, please use `chi.RegisterMethod("LINK")` and `chi.RegisterMethod("UNLINK")` in an `init()` function
|
||||
|
||||
|
||||
## v3.2.1 (2017-08-31)
|
||||
|
||||
- Add new `Match(rctx *Context, method, path string) bool` method to `Routes` interface
|
||||
and `Mux`. Match searches the mux's routing tree for a handler that matches the method/path
|
||||
- Add new `RouteMethod` to `*Context`
|
||||
- Add new `Routes` pointer to `*Context`
|
||||
- Add new `middleware.GetHead` to route missing HEAD requests to GET handler
|
||||
- Updated benchmarks (see README)
|
||||
|
||||
|
||||
## v3.1.5 (2017-08-02)
|
||||
|
||||
- Setup golint and go vet for the project
|
||||
- As per golint, we've redefined `func ServerBaseContext(h http.Handler, baseCtx context.Context) http.Handler`
|
||||
to `func ServerBaseContext(baseCtx context.Context, h http.Handler) http.Handler`
|
||||
|
||||
|
||||
## v3.1.0 (2017-07-10)
|
||||
|
||||
- Fix a few minor issues after v3 release
|
||||
- Move `docgen` sub-pkg to https://github.com/go-chi/docgen
|
||||
- Move `render` sub-pkg to https://github.com/go-chi/render
|
||||
- Add new `URLFormat` handler to chi/middleware sub-pkg to make working with url mime
|
||||
suffixes easier, ie. parsing `/articles/1.json` and `/articles/1.xml`. See comments in
|
||||
https://github.com/go-chi/chi/blob/master/middleware/url_format.go for example usage.
|
||||
|
||||
|
||||
## v3.0.0 (2017-06-21)
|
||||
|
||||
- Major update to chi library with many exciting updates, but also some *breaking changes*
|
||||
- URL parameter syntax changed from `/:id` to `/{id}` for even more flexible routing, such as
|
||||
`/articles/{month}-{day}-{year}-{slug}`, `/articles/{id}`, and `/articles/{id}.{ext}` on the
|
||||
same router
|
||||
- Support for regexp for routing patterns, in the form of `/{paramKey:regExp}` for example:
|
||||
`r.Get("/articles/{name:[a-z]+}", h)` and `chi.URLParam(r, "name")`
|
||||
- Add `Method` and `MethodFunc` to `chi.Router` to allow routing definitions such as
|
||||
`r.Method("GET", "/", h)` which provides a cleaner interface for custom handlers like
|
||||
in `_examples/custom-handler`
|
||||
- Deprecating `mux#FileServer` helper function. Instead, we encourage users to create their
|
||||
own using file handler with the stdlib, see `_examples/fileserver` for an example
|
||||
- Add support for LINK/UNLINK http methods via `r.Method()` and `r.MethodFunc()`
|
||||
- Moved the chi project to its own organization, to allow chi-related community packages to
|
||||
be easily discovered and supported, at: https://github.com/go-chi
|
||||
- *NOTE:* please update your import paths to `"github.com/go-chi/chi"`
|
||||
- *NOTE:* chi v2 is still available at https://github.com/go-chi/chi/tree/v2
|
||||
|
||||
|
||||
## v2.1.0 (2017-03-30)
|
||||
|
||||
- Minor improvements and update to the chi core library
|
||||
- Introduced a brand new `chi/render` sub-package to complete the story of building
|
||||
APIs to offer a pattern for managing well-defined request / response payloads. Please
|
||||
check out the updated `_examples/rest` example for how it works.
|
||||
- Added `MethodNotAllowed(h http.HandlerFunc)` to chi.Router interface
|
||||
|
||||
|
||||
## v2.0.0 (2017-01-06)
|
||||
|
||||
- After many months of v2 being in an RC state with many companies and users running it in
|
||||
production, the inclusion of some improvements to the middlewares, we are very pleased to
|
||||
announce v2.0.0 of chi.
|
||||
|
||||
|
||||
## v2.0.0-rc1 (2016-07-26)
|
||||
|
||||
- Huge update! chi v2 is a large refactor targetting Go 1.7+. As of Go 1.7, the popular
|
||||
community `"net/context"` package has been included in the standard library as `"context"` and
|
||||
utilized by `"net/http"` and `http.Request` to managing deadlines, cancelation signals and other
|
||||
request-scoped values. We're very excited about the new context addition and are proud to
|
||||
introduce chi v2, a minimal and powerful routing package for building large HTTP services,
|
||||
with zero external dependencies. Chi focuses on idiomatic design and encourages the use of
|
||||
stdlib HTTP handlers and middlwares.
|
||||
- chi v2 deprecates its `chi.Handler` interface and requires `http.Handler` or `http.HandlerFunc`
|
||||
- chi v2 stores URL routing parameters and patterns in the standard request context: `r.Context()`
|
||||
- chi v2 lower-level routing context is accessible by `chi.RouteContext(r.Context()) *chi.Context`,
|
||||
which provides direct access to URL routing parameters, the routing path and the matching
|
||||
routing patterns.
|
||||
- Users upgrading from chi v1 to v2, need to:
|
||||
1. Update the old chi.Handler signature, `func(ctx context.Context, w http.ResponseWriter, r *http.Request)` to
|
||||
the standard http.Handler: `func(w http.ResponseWriter, r *http.Request)`
|
||||
2. Use `chi.URLParam(r *http.Request, paramKey string) string`
|
||||
or `URLParamFromCtx(ctx context.Context, paramKey string) string` to access a url parameter value
|
||||
|
||||
|
||||
## v1.0.0 (2016-07-01)
|
||||
|
||||
- Released chi v1 stable https://github.com/go-chi/chi/tree/v1.0.0 for Go 1.6 and older.
|
||||
|
||||
|
||||
## v0.9.0 (2016-03-31)
|
||||
|
||||
- Reuse context objects via sync.Pool for zero-allocation routing [#33](https://github.com/go-chi/chi/pull/33)
|
||||
- BREAKING NOTE: due to subtle API changes, previously `chi.URLParams(ctx)["id"]` used to access url parameters
|
||||
has changed to: `chi.URLParam(ctx, "id")`
|
||||
31
vendor/github.com/go-chi/chi/v5/CONTRIBUTING.md
generated
vendored
Normal file
31
vendor/github.com/go-chi/chi/v5/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# Contributing
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. [Install Go][go-install].
|
||||
2. Download the sources and switch the working directory:
|
||||
|
||||
```bash
|
||||
go get -u -d github.com/go-chi/chi
|
||||
cd $GOPATH/src/github.com/go-chi/chi
|
||||
```
|
||||
|
||||
## Submitting a Pull Request
|
||||
|
||||
A typical workflow is:
|
||||
|
||||
1. [Fork the repository.][fork] [This tip maybe also helpful.][go-fork-tip]
|
||||
2. [Create a topic branch.][branch]
|
||||
3. Add tests for your change.
|
||||
4. Run `go test`. If your tests pass, return to the step 3.
|
||||
5. Implement the change and ensure the steps from the previous step pass.
|
||||
6. Run `goimports -w .`, to ensure the new code conforms to Go formatting guideline.
|
||||
7. [Add, commit and push your changes.][git-help]
|
||||
8. [Submit a pull request.][pull-req]
|
||||
|
||||
[go-install]: https://golang.org/doc/install
|
||||
[go-fork-tip]: http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html
|
||||
[fork]: https://help.github.com/articles/fork-a-repo
|
||||
[branch]: http://learn.github.com/p/branching.html
|
||||
[git-help]: https://guides.github.com
|
||||
[pull-req]: https://help.github.com/articles/using-pull-requests
|
||||
20
vendor/github.com/go-chi/chi/v5/LICENSE
generated
vendored
Normal file
20
vendor/github.com/go-chi/chi/v5/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2015-present Peter Kieltyka (https://github.com/pkieltyka), Google Inc.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
14
vendor/github.com/go-chi/chi/v5/Makefile
generated
vendored
Normal file
14
vendor/github.com/go-chi/chi/v5/Makefile
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
all:
|
||||
@echo "**********************************************************"
|
||||
@echo "** chi build tool **"
|
||||
@echo "**********************************************************"
|
||||
|
||||
|
||||
test:
|
||||
go clean -testcache && $(MAKE) test-router && $(MAKE) test-middleware
|
||||
|
||||
test-router:
|
||||
go test -race -v .
|
||||
|
||||
test-middleware:
|
||||
go test -race -v ./middleware
|
||||
511
vendor/github.com/go-chi/chi/v5/README.md
generated
vendored
Normal file
511
vendor/github.com/go-chi/chi/v5/README.md
generated
vendored
Normal file
@@ -0,0 +1,511 @@
|
||||
# <img alt="chi" src="https://cdn.rawgit.com/go-chi/chi/master/_examples/chi.svg" width="220" />
|
||||
|
||||
|
||||
[![GoDoc Widget]][GoDoc] [![Travis Widget]][Travis]
|
||||
|
||||
`chi` is a lightweight, idiomatic and composable router for building Go HTTP services. It's
|
||||
especially good at helping you write large REST API services that are kept maintainable as your
|
||||
project grows and changes. `chi` is built on the new `context` package introduced in Go 1.7 to
|
||||
handle signaling, cancelation and request-scoped values across a handler chain.
|
||||
|
||||
The focus of the project has been to seek out an elegant and comfortable design for writing
|
||||
REST API servers, written during the development of the Pressly API service that powers our
|
||||
public API service, which in turn powers all of our client-side applications.
|
||||
|
||||
The key considerations of chi's design are: project structure, maintainability, standard http
|
||||
handlers (stdlib-only), developer productivity, and deconstructing a large system into many small
|
||||
parts. The core router `github.com/go-chi/chi` is quite small (less than 1000 LOC), but we've also
|
||||
included some useful/optional subpackages: [middleware](/middleware), [render](https://github.com/go-chi/render)
|
||||
and [docgen](https://github.com/go-chi/docgen). We hope you enjoy it too!
|
||||
|
||||
## Install
|
||||
|
||||
`go get -u github.com/go-chi/chi/v5`
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
* **Lightweight** - cloc'd in ~1000 LOC for the chi router
|
||||
* **Fast** - yes, see [benchmarks](#benchmarks)
|
||||
* **100% compatible with net/http** - use any http or middleware pkg in the ecosystem that is also compatible with `net/http`
|
||||
* **Designed for modular/composable APIs** - middlewares, inline middlewares, route groups and sub-router mounting
|
||||
* **Context control** - built on new `context` package, providing value chaining, cancellations and timeouts
|
||||
* **Robust** - in production at Pressly, CloudFlare, Heroku, 99Designs, and many others (see [discussion](https://github.com/go-chi/chi/issues/91))
|
||||
* **Doc generation** - `docgen` auto-generates routing documentation from your source to JSON or Markdown
|
||||
* **Go.mod support** - v1.x of chi (starting from v1.5.0), now has go.mod support (see [CHANGELOG](https://github.com/go-chi/chi/blob/master/CHANGELOG.md#v150-2020-11-12---now-with-gomod-support))
|
||||
* **No external dependencies** - plain ol' Go stdlib + net/http
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
See [_examples/](https://github.com/go-chi/chi/blob/master/_examples/) for a variety of examples.
|
||||
|
||||
|
||||
**As easy as:**
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := chi.NewRouter()
|
||||
r.Use(middleware.Logger)
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("welcome"))
|
||||
})
|
||||
http.ListenAndServe(":3000", r)
|
||||
}
|
||||
```
|
||||
|
||||
**REST Preview:**
|
||||
|
||||
Here is a little preview of how routing looks like with chi. Also take a look at the generated routing docs
|
||||
in JSON ([routes.json](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.json)) and in
|
||||
Markdown ([routes.md](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.md)).
|
||||
|
||||
I highly recommend reading the source of the [examples](https://github.com/go-chi/chi/blob/master/_examples/) listed
|
||||
above, they will show you all the features of chi and serve as a good form of documentation.
|
||||
|
||||
```go
|
||||
import (
|
||||
//...
|
||||
"context"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r := chi.NewRouter()
|
||||
|
||||
// A good base middleware stack
|
||||
r.Use(middleware.RequestID)
|
||||
r.Use(middleware.RealIP)
|
||||
r.Use(middleware.Logger)
|
||||
r.Use(middleware.Recoverer)
|
||||
|
||||
// Set a timeout value on the request context (ctx), that will signal
|
||||
// through ctx.Done() that the request has timed out and further
|
||||
// processing should be stopped.
|
||||
r.Use(middleware.Timeout(60 * time.Second))
|
||||
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("hi"))
|
||||
})
|
||||
|
||||
// RESTy routes for "articles" resource
|
||||
r.Route("/articles", func(r chi.Router) {
|
||||
r.With(paginate).Get("/", listArticles) // GET /articles
|
||||
r.With(paginate).Get("/{month}-{day}-{year}", listArticlesByDate) // GET /articles/01-16-2017
|
||||
|
||||
r.Post("/", createArticle) // POST /articles
|
||||
r.Get("/search", searchArticles) // GET /articles/search
|
||||
|
||||
// Regexp url parameters:
|
||||
r.Get("/{articleSlug:[a-z-]+}", getArticleBySlug) // GET /articles/home-is-toronto
|
||||
|
||||
// Subrouters:
|
||||
r.Route("/{articleID}", func(r chi.Router) {
|
||||
r.Use(ArticleCtx)
|
||||
r.Get("/", getArticle) // GET /articles/123
|
||||
r.Put("/", updateArticle) // PUT /articles/123
|
||||
r.Delete("/", deleteArticle) // DELETE /articles/123
|
||||
})
|
||||
})
|
||||
|
||||
// Mount the admin sub-router
|
||||
r.Mount("/admin", adminRouter())
|
||||
|
||||
http.ListenAndServe(":3333", r)
|
||||
}
|
||||
|
||||
func ArticleCtx(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
articleID := chi.URLParam(r, "articleID")
|
||||
article, err := dbGetArticle(articleID)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
ctx := context.WithValue(r.Context(), "article", article)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
func getArticle(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
article, ok := ctx.Value("article").(*Article)
|
||||
if !ok {
|
||||
http.Error(w, http.StatusText(422), 422)
|
||||
return
|
||||
}
|
||||
w.Write([]byte(fmt.Sprintf("title:%s", article.Title)))
|
||||
}
|
||||
|
||||
// A completely separate router for administrator routes
|
||||
func adminRouter() http.Handler {
|
||||
r := chi.NewRouter()
|
||||
r.Use(AdminOnly)
|
||||
r.Get("/", adminIndex)
|
||||
r.Get("/accounts", adminListAccounts)
|
||||
return r
|
||||
}
|
||||
|
||||
func AdminOnly(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
perm, ok := ctx.Value("acl.permission").(YourPermissionType)
|
||||
if !ok || !perm.IsAdmin() {
|
||||
http.Error(w, http.StatusText(403), 403)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Router interface
|
||||
|
||||
chi's router is based on a kind of [Patricia Radix trie](https://en.wikipedia.org/wiki/Radix_tree).
|
||||
The router is fully compatible with `net/http`.
|
||||
|
||||
Built on top of the tree is the `Router` interface:
|
||||
|
||||
```go
|
||||
// Router consisting of the core routing methods used by chi's Mux,
|
||||
// using only the standard net/http.
|
||||
type Router interface {
|
||||
http.Handler
|
||||
Routes
|
||||
|
||||
// Use appends one or more middlewares onto the Router stack.
|
||||
Use(middlewares ...func(http.Handler) http.Handler)
|
||||
|
||||
// With adds inline middlewares for an endpoint handler.
|
||||
With(middlewares ...func(http.Handler) http.Handler) Router
|
||||
|
||||
// Group adds a new inline-Router along the current routing
|
||||
// path, with a fresh middleware stack for the inline-Router.
|
||||
Group(fn func(r Router)) Router
|
||||
|
||||
// Route mounts a sub-Router along a `pattern`` string.
|
||||
Route(pattern string, fn func(r Router)) Router
|
||||
|
||||
// Mount attaches another http.Handler along ./pattern/*
|
||||
Mount(pattern string, h http.Handler)
|
||||
|
||||
// Handle and HandleFunc adds routes for `pattern` that matches
|
||||
// all HTTP methods.
|
||||
Handle(pattern string, h http.Handler)
|
||||
HandleFunc(pattern string, h http.HandlerFunc)
|
||||
|
||||
// Method and MethodFunc adds routes for `pattern` that matches
|
||||
// the `method` HTTP method.
|
||||
Method(method, pattern string, h http.Handler)
|
||||
MethodFunc(method, pattern string, h http.HandlerFunc)
|
||||
|
||||
// HTTP-method routing along `pattern`
|
||||
Connect(pattern string, h http.HandlerFunc)
|
||||
Delete(pattern string, h http.HandlerFunc)
|
||||
Get(pattern string, h http.HandlerFunc)
|
||||
Head(pattern string, h http.HandlerFunc)
|
||||
Options(pattern string, h http.HandlerFunc)
|
||||
Patch(pattern string, h http.HandlerFunc)
|
||||
Post(pattern string, h http.HandlerFunc)
|
||||
Put(pattern string, h http.HandlerFunc)
|
||||
Trace(pattern string, h http.HandlerFunc)
|
||||
|
||||
// NotFound defines a handler to respond whenever a route could
|
||||
// not be found.
|
||||
NotFound(h http.HandlerFunc)
|
||||
|
||||
// MethodNotAllowed defines a handler to respond whenever a method is
|
||||
// not allowed.
|
||||
MethodNotAllowed(h http.HandlerFunc)
|
||||
}
|
||||
|
||||
// Routes interface adds two methods for router traversal, which is also
|
||||
// used by the github.com/go-chi/docgen package to generate documentation for Routers.
|
||||
type Routes interface {
|
||||
// Routes returns the routing tree in an easily traversable structure.
|
||||
Routes() []Route
|
||||
|
||||
// Middlewares returns the list of middlewares in use by the router.
|
||||
Middlewares() Middlewares
|
||||
|
||||
// Match searches the routing tree for a handler that matches
|
||||
// the method/path - similar to routing a http request, but without
|
||||
// executing the handler thereafter.
|
||||
Match(rctx *Context, method, path string) bool
|
||||
}
|
||||
```
|
||||
|
||||
Each routing method accepts a URL `pattern` and chain of `handlers`. The URL pattern
|
||||
supports named params (ie. `/users/{userID}`) and wildcards (ie. `/admin/*`). URL parameters
|
||||
can be fetched at runtime by calling `chi.URLParam(r, "userID")` for named parameters
|
||||
and `chi.URLParam(r, "*")` for a wildcard parameter.
|
||||
|
||||
|
||||
### Middleware handlers
|
||||
|
||||
chi's middlewares are just stdlib net/http middleware handlers. There is nothing special
|
||||
about them, which means the router and all the tooling is designed to be compatible and
|
||||
friendly with any middleware in the community. This offers much better extensibility and reuse
|
||||
of packages and is at the heart of chi's purpose.
|
||||
|
||||
Here is an example of a standard net/http middleware where we assign a context key `"user"`
|
||||
the value of `"123"`. This middleware sets a hypothetical user identifier on the request
|
||||
context and calls the next handler in the chain.
|
||||
|
||||
```go
|
||||
// HTTP middleware setting a value on the request context
|
||||
func MyMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// create new context from `r` request context, and assign key `"user"`
|
||||
// to value of `"123"`
|
||||
ctx := context.WithValue(r.Context(), "user", "123")
|
||||
|
||||
// call the next handler in the chain, passing the response writer and
|
||||
// the updated request object with the new context value.
|
||||
//
|
||||
// note: context.Context values are nested, so any previously set
|
||||
// values will be accessible as well, and the new `"user"` key
|
||||
// will be accessible from this point forward.
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Request handlers
|
||||
|
||||
chi uses standard net/http request handlers. This little snippet is an example of a http.Handler
|
||||
func that reads a user identifier from the request context - hypothetically, identifying
|
||||
the user sending an authenticated request, validated+set by a previous middleware handler.
|
||||
|
||||
```go
|
||||
// HTTP handler accessing data from the request context.
|
||||
func MyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// here we read from the request context and fetch out `"user"` key set in
|
||||
// the MyMiddleware example above.
|
||||
user := r.Context().Value("user").(string)
|
||||
|
||||
// respond to the client
|
||||
w.Write([]byte(fmt.Sprintf("hi %s", user)))
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### URL parameters
|
||||
|
||||
chi's router parses and stores URL parameters right onto the request context. Here is
|
||||
an example of how to access URL params in your net/http handlers. And of course, middlewares
|
||||
are able to access the same information.
|
||||
|
||||
```go
|
||||
// HTTP handler accessing the url routing parameters.
|
||||
func MyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// fetch the url parameter `"userID"` from the request of a matching
|
||||
// routing pattern. An example routing pattern could be: /users/{userID}
|
||||
userID := chi.URLParam(r, "userID")
|
||||
|
||||
// fetch `"key"` from the request context
|
||||
ctx := r.Context()
|
||||
key := ctx.Value("key").(string)
|
||||
|
||||
// respond to the client
|
||||
w.Write([]byte(fmt.Sprintf("hi %v, %v", userID, key)))
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Middlewares
|
||||
|
||||
chi comes equipped with an optional `middleware` package, providing a suite of standard
|
||||
`net/http` middlewares. Please note, any middleware in the ecosystem that is also compatible
|
||||
with `net/http` can be used with chi's mux.
|
||||
|
||||
### Core middlewares
|
||||
|
||||
----------------------------------------------------------------------------------------------------
|
||||
| chi/middleware Handler | description |
|
||||
| :--------------------- | :---------------------------------------------------------------------- |
|
||||
| [AllowContentEncoding] | Enforces a whitelist of request Content-Encoding headers |
|
||||
| [AllowContentType] | Explicit whitelist of accepted request Content-Types |
|
||||
| [BasicAuth] | Basic HTTP authentication |
|
||||
| [Compress] | Gzip compression for clients that accept compressed responses |
|
||||
| [ContentCharset] | Ensure charset for Content-Type request headers |
|
||||
| [CleanPath] | Clean double slashes from request path |
|
||||
| [GetHead] | Automatically route undefined HEAD requests to GET handlers |
|
||||
| [Heartbeat] | Monitoring endpoint to check the servers pulse |
|
||||
| [Logger] | Logs the start and end of each request with the elapsed processing time |
|
||||
| [NoCache] | Sets response headers to prevent clients from caching |
|
||||
| [Profiler] | Easily attach net/http/pprof to your routers |
|
||||
| [RealIP] | Sets a http.Request's RemoteAddr to either X-Forwarded-For or X-Real-IP |
|
||||
| [Recoverer] | Gracefully absorb panics and prints the stack trace |
|
||||
| [RequestID] | Injects a request ID into the context of each request |
|
||||
| [RedirectSlashes] | Redirect slashes on routing paths |
|
||||
| [RouteHeaders] | Route handling for request headers |
|
||||
| [SetHeader] | Short-hand middleware to set a response header key/value |
|
||||
| [StripSlashes] | Strip slashes on routing paths |
|
||||
| [Throttle] | Puts a ceiling on the number of concurrent requests |
|
||||
| [Timeout] | Signals to the request context when the timeout deadline is reached |
|
||||
| [URLFormat] | Parse extension from url and put it on request context |
|
||||
| [WithValue] | Short-hand middleware to set a key/value on the request context |
|
||||
----------------------------------------------------------------------------------------------------
|
||||
|
||||
[AllowContentEncoding]: https://pkg.go.dev/github.com/go-chi/chi/middleware#AllowContentEncoding
|
||||
[AllowContentType]: https://pkg.go.dev/github.com/go-chi/chi/middleware#AllowContentType
|
||||
[BasicAuth]: https://pkg.go.dev/github.com/go-chi/chi/middleware#BasicAuth
|
||||
[Compress]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Compress
|
||||
[ContentCharset]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ContentCharset
|
||||
[CleanPath]: https://pkg.go.dev/github.com/go-chi/chi/middleware#CleanPath
|
||||
[GetHead]: https://pkg.go.dev/github.com/go-chi/chi/middleware#GetHead
|
||||
[GetReqID]: https://pkg.go.dev/github.com/go-chi/chi/middleware#GetReqID
|
||||
[Heartbeat]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Heartbeat
|
||||
[Logger]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Logger
|
||||
[NoCache]: https://pkg.go.dev/github.com/go-chi/chi/middleware#NoCache
|
||||
[Profiler]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Profiler
|
||||
[RealIP]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RealIP
|
||||
[Recoverer]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Recoverer
|
||||
[RedirectSlashes]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RedirectSlashes
|
||||
[RequestLogger]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RequestLogger
|
||||
[RequestID]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RequestID
|
||||
[RouteHeaders]: https://pkg.go.dev/github.com/go-chi/chi/middleware#RouteHeaders
|
||||
[SetHeader]: https://pkg.go.dev/github.com/go-chi/chi/middleware#SetHeader
|
||||
[StripSlashes]: https://pkg.go.dev/github.com/go-chi/chi/middleware#StripSlashes
|
||||
[Throttle]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Throttle
|
||||
[ThrottleBacklog]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ThrottleBacklog
|
||||
[ThrottleWithOpts]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ThrottleWithOpts
|
||||
[Timeout]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Timeout
|
||||
[URLFormat]: https://pkg.go.dev/github.com/go-chi/chi/middleware#URLFormat
|
||||
[WithLogEntry]: https://pkg.go.dev/github.com/go-chi/chi/middleware#WithLogEntry
|
||||
[WithValue]: https://pkg.go.dev/github.com/go-chi/chi/middleware#WithValue
|
||||
[Compressor]: https://pkg.go.dev/github.com/go-chi/chi/middleware#Compressor
|
||||
[DefaultLogFormatter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#DefaultLogFormatter
|
||||
[EncoderFunc]: https://pkg.go.dev/github.com/go-chi/chi/middleware#EncoderFunc
|
||||
[HeaderRoute]: https://pkg.go.dev/github.com/go-chi/chi/middleware#HeaderRoute
|
||||
[HeaderRouter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#HeaderRouter
|
||||
[LogEntry]: https://pkg.go.dev/github.com/go-chi/chi/middleware#LogEntry
|
||||
[LogFormatter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#LogFormatter
|
||||
[LoggerInterface]: https://pkg.go.dev/github.com/go-chi/chi/middleware#LoggerInterface
|
||||
[ThrottleOpts]: https://pkg.go.dev/github.com/go-chi/chi/middleware#ThrottleOpts
|
||||
[WrapResponseWriter]: https://pkg.go.dev/github.com/go-chi/chi/middleware#WrapResponseWriter
|
||||
|
||||
### Extra middlewares & packages
|
||||
|
||||
Please see https://github.com/go-chi for additional packages.
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------
|
||||
| package | description |
|
||||
|:---------------------------------------------------|:-------------------------------------------------------------
|
||||
| [cors](https://github.com/go-chi/cors) | Cross-origin resource sharing (CORS) |
|
||||
| [docgen](https://github.com/go-chi/docgen) | Print chi.Router routes at runtime |
|
||||
| [jwtauth](https://github.com/go-chi/jwtauth) | JWT authentication |
|
||||
| [hostrouter](https://github.com/go-chi/hostrouter) | Domain/host based request routing |
|
||||
| [httplog](https://github.com/go-chi/httplog) | Small but powerful structured HTTP request logging |
|
||||
| [httprate](https://github.com/go-chi/httprate) | HTTP request rate limiter |
|
||||
| [httptracer](https://github.com/go-chi/httptracer) | HTTP request performance tracing library |
|
||||
| [httpvcr](https://github.com/go-chi/httpvcr) | Write deterministic tests for external sources |
|
||||
| [stampede](https://github.com/go-chi/stampede) | HTTP request coalescer |
|
||||
--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## context?
|
||||
|
||||
`context` is a tiny pkg that provides simple interface to signal context across call stacks
|
||||
and goroutines. It was originally written by [Sameer Ajmani](https://github.com/Sajmani)
|
||||
and is available in stdlib since go1.7.
|
||||
|
||||
Learn more at https://blog.golang.org/context
|
||||
|
||||
and..
|
||||
* Docs: https://golang.org/pkg/context
|
||||
* Source: https://github.com/golang/go/tree/master/src/context
|
||||
|
||||
|
||||
## Benchmarks
|
||||
|
||||
The benchmark suite: https://github.com/pkieltyka/go-http-routing-benchmark
|
||||
|
||||
Results as of Nov 29, 2020 with Go 1.15.5 on Linux AMD 3950x
|
||||
|
||||
```shell
|
||||
BenchmarkChi_Param 3075895 384 ns/op 400 B/op 2 allocs/op
|
||||
BenchmarkChi_Param5 2116603 566 ns/op 400 B/op 2 allocs/op
|
||||
BenchmarkChi_Param20 964117 1227 ns/op 400 B/op 2 allocs/op
|
||||
BenchmarkChi_ParamWrite 2863413 420 ns/op 400 B/op 2 allocs/op
|
||||
BenchmarkChi_GithubStatic 3045488 395 ns/op 400 B/op 2 allocs/op
|
||||
BenchmarkChi_GithubParam 2204115 540 ns/op 400 B/op 2 allocs/op
|
||||
BenchmarkChi_GithubAll 10000 113811 ns/op 81203 B/op 406 allocs/op
|
||||
BenchmarkChi_GPlusStatic 3337485 359 ns/op 400 B/op 2 allocs/op
|
||||
BenchmarkChi_GPlusParam 2825853 423 ns/op 400 B/op 2 allocs/op
|
||||
BenchmarkChi_GPlus2Params 2471697 483 ns/op 400 B/op 2 allocs/op
|
||||
BenchmarkChi_GPlusAll 194220 5950 ns/op 5200 B/op 26 allocs/op
|
||||
BenchmarkChi_ParseStatic 3365324 356 ns/op 400 B/op 2 allocs/op
|
||||
BenchmarkChi_ParseParam 2976614 404 ns/op 400 B/op 2 allocs/op
|
||||
BenchmarkChi_Parse2Params 2638084 439 ns/op 400 B/op 2 allocs/op
|
||||
BenchmarkChi_ParseAll 109567 11295 ns/op 10400 B/op 52 allocs/op
|
||||
BenchmarkChi_StaticAll 16846 71308 ns/op 62802 B/op 314 allocs/op
|
||||
```
|
||||
|
||||
Comparison with other routers: https://gist.github.com/pkieltyka/123032f12052520aaccab752bd3e78cc
|
||||
|
||||
NOTE: the allocs in the benchmark above are from the calls to http.Request's
|
||||
`WithContext(context.Context)` method that clones the http.Request, sets the `Context()`
|
||||
on the duplicated (alloc'd) request and returns it the new request object. This is just
|
||||
how setting context on a request in Go works.
|
||||
|
||||
|
||||
## Go module support & note on chi's versioning
|
||||
|
||||
* Go.mod support means we reset our versioning starting from v1.5 (see [CHANGELOG](https://github.com/go-chi/chi/blob/master/CHANGELOG.md#v150-2020-11-12---now-with-gomod-support))
|
||||
* All older tags are preserved, are backwards-compatible and will "just work" as they
|
||||
* Brand new systems can run `go get -u github.com/go-chi/chi` as normal, or `go get -u github.com/go-chi/chi@latest`
|
||||
to install chi, which will install v1.x+ built with go.mod support, starting from v1.5.0.
|
||||
* For existing projects who want to upgrade to the latest go.mod version, run: `go get -u github.com/go-chi/chi@v1.5.0`,
|
||||
which will get you on the go.mod version line (as Go's mod cache may still remember v4.x).
|
||||
* Any breaking changes will bump a "minor" release and backwards-compatible improvements/fixes will bump a "tiny" release.
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
* Carl Jackson for https://github.com/zenazn/goji
|
||||
* Parts of chi's thinking comes from goji, and chi's middleware package
|
||||
sources from goji.
|
||||
* Armon Dadgar for https://github.com/armon/go-radix
|
||||
* Contributions: [@VojtechVitek](https://github.com/VojtechVitek)
|
||||
|
||||
We'll be more than happy to see [your contributions](./CONTRIBUTING.md)!
|
||||
|
||||
|
||||
## Beyond REST
|
||||
|
||||
chi is just a http router that lets you decompose request handling into many smaller layers.
|
||||
Many companies use chi to write REST services for their public APIs. But, REST is just a convention
|
||||
for managing state via HTTP, and there's a lot of other pieces required to write a complete client-server
|
||||
system or network of microservices.
|
||||
|
||||
Looking beyond REST, I also recommend some newer works in the field:
|
||||
* [webrpc](https://github.com/webrpc/webrpc) - Web-focused RPC client+server framework with code-gen
|
||||
* [gRPC](https://github.com/grpc/grpc-go) - Google's RPC framework via protobufs
|
||||
* [graphql](https://github.com/99designs/gqlgen) - Declarative query language
|
||||
* [NATS](https://nats.io) - lightweight pub-sub
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2015-present [Peter Kieltyka](https://github.com/pkieltyka)
|
||||
|
||||
Licensed under [MIT License](./LICENSE)
|
||||
|
||||
[GoDoc]: https://pkg.go.dev/github.com/go-chi/chi?tab=versions
|
||||
[GoDoc Widget]: https://godoc.org/github.com/go-chi/chi?status.svg
|
||||
[Travis]: https://travis-ci.org/go-chi/chi
|
||||
[Travis Widget]: https://travis-ci.org/go-chi/chi.svg?branch=master
|
||||
49
vendor/github.com/go-chi/chi/v5/chain.go
generated
vendored
Normal file
49
vendor/github.com/go-chi/chi/v5/chain.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package chi
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Chain returns a Middlewares type from a slice of middleware handlers.
|
||||
func Chain(middlewares ...func(http.Handler) http.Handler) Middlewares {
|
||||
return Middlewares(middlewares)
|
||||
}
|
||||
|
||||
// Handler builds and returns a http.Handler from the chain of middlewares,
|
||||
// with `h http.Handler` as the final handler.
|
||||
func (mws Middlewares) Handler(h http.Handler) http.Handler {
|
||||
return &ChainHandler{mws, h, chain(mws, h)}
|
||||
}
|
||||
|
||||
// HandlerFunc builds and returns a http.Handler from the chain of middlewares,
|
||||
// with `h http.Handler` as the final handler.
|
||||
func (mws Middlewares) HandlerFunc(h http.HandlerFunc) http.Handler {
|
||||
return &ChainHandler{mws, h, chain(mws, h)}
|
||||
}
|
||||
|
||||
// ChainHandler is a http.Handler with support for handler composition and
|
||||
// execution.
|
||||
type ChainHandler struct {
|
||||
Middlewares Middlewares
|
||||
Endpoint http.Handler
|
||||
chain http.Handler
|
||||
}
|
||||
|
||||
func (c *ChainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
c.chain.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// chain builds a http.Handler composed of an inline middleware stack and endpoint
|
||||
// handler in the order they are passed.
|
||||
func chain(middlewares []func(http.Handler) http.Handler, endpoint http.Handler) http.Handler {
|
||||
// Return ahead of time if there aren't any middlewares for the chain
|
||||
if len(middlewares) == 0 {
|
||||
return endpoint
|
||||
}
|
||||
|
||||
// Wrap the end handler with the middleware chain
|
||||
h := middlewares[len(middlewares)-1](endpoint)
|
||||
for i := len(middlewares) - 2; i >= 0; i-- {
|
||||
h = middlewares[i](h)
|
||||
}
|
||||
|
||||
return h
|
||||
}
|
||||
134
vendor/github.com/go-chi/chi/v5/chi.go
generated
vendored
Normal file
134
vendor/github.com/go-chi/chi/v5/chi.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// Package chi is a small, idiomatic and composable router for building HTTP services.
|
||||
//
|
||||
// chi requires Go 1.10 or newer.
|
||||
//
|
||||
// Example:
|
||||
// package main
|
||||
//
|
||||
// import (
|
||||
// "net/http"
|
||||
//
|
||||
// "github.com/go-chi/chi/v5"
|
||||
// "github.com/go-chi/chi/v5/middleware"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
// r := chi.NewRouter()
|
||||
// r.Use(middleware.Logger)
|
||||
// r.Use(middleware.Recoverer)
|
||||
//
|
||||
// r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
// w.Write([]byte("root."))
|
||||
// })
|
||||
//
|
||||
// http.ListenAndServe(":3333", r)
|
||||
// }
|
||||
//
|
||||
// See github.com/go-chi/chi/_examples/ for more in-depth examples.
|
||||
//
|
||||
// URL patterns allow for easy matching of path components in HTTP
|
||||
// requests. The matching components can then be accessed using
|
||||
// chi.URLParam(). All patterns must begin with a slash.
|
||||
//
|
||||
// A simple named placeholder {name} matches any sequence of characters
|
||||
// up to the next / or the end of the URL. Trailing slashes on paths must
|
||||
// be handled explicitly.
|
||||
//
|
||||
// A placeholder with a name followed by a colon allows a regular
|
||||
// expression match, for example {number:\\d+}. The regular expression
|
||||
// syntax is Go's normal regexp RE2 syntax, except that regular expressions
|
||||
// including { or } are not supported, and / will never be
|
||||
// matched. An anonymous regexp pattern is allowed, using an empty string
|
||||
// before the colon in the placeholder, such as {:\\d+}
|
||||
//
|
||||
// The special placeholder of asterisk matches the rest of the requested
|
||||
// URL. Any trailing characters in the pattern are ignored. This is the only
|
||||
// placeholder which will match / characters.
|
||||
//
|
||||
// Examples:
|
||||
// "/user/{name}" matches "/user/jsmith" but not "/user/jsmith/info" or "/user/jsmith/"
|
||||
// "/user/{name}/info" matches "/user/jsmith/info"
|
||||
// "/page/*" matches "/page/intro/latest"
|
||||
// "/page/*/index" also matches "/page/intro/latest"
|
||||
// "/date/{yyyy:\\d\\d\\d\\d}/{mm:\\d\\d}/{dd:\\d\\d}" matches "/date/2017/04/01"
|
||||
//
|
||||
package chi
|
||||
|
||||
import "net/http"
|
||||
|
||||
// NewRouter returns a new Mux object that implements the Router interface.
|
||||
func NewRouter() *Mux {
|
||||
return NewMux()
|
||||
}
|
||||
|
||||
// Router consisting of the core routing methods used by chi's Mux,
|
||||
// using only the standard net/http.
|
||||
type Router interface {
|
||||
http.Handler
|
||||
Routes
|
||||
|
||||
// Use appends one or more middlewares onto the Router stack.
|
||||
Use(middlewares ...func(http.Handler) http.Handler)
|
||||
|
||||
// With adds inline middlewares for an endpoint handler.
|
||||
With(middlewares ...func(http.Handler) http.Handler) Router
|
||||
|
||||
// Group adds a new inline-Router along the current routing
|
||||
// path, with a fresh middleware stack for the inline-Router.
|
||||
Group(fn func(r Router)) Router
|
||||
|
||||
// Route mounts a sub-Router along a `pattern`` string.
|
||||
Route(pattern string, fn func(r Router)) Router
|
||||
|
||||
// Mount attaches another http.Handler along ./pattern/*
|
||||
Mount(pattern string, h http.Handler)
|
||||
|
||||
// Handle and HandleFunc adds routes for `pattern` that matches
|
||||
// all HTTP methods.
|
||||
Handle(pattern string, h http.Handler)
|
||||
HandleFunc(pattern string, h http.HandlerFunc)
|
||||
|
||||
// Method and MethodFunc adds routes for `pattern` that matches
|
||||
// the `method` HTTP method.
|
||||
Method(method, pattern string, h http.Handler)
|
||||
MethodFunc(method, pattern string, h http.HandlerFunc)
|
||||
|
||||
// HTTP-method routing along `pattern`
|
||||
Connect(pattern string, h http.HandlerFunc)
|
||||
Delete(pattern string, h http.HandlerFunc)
|
||||
Get(pattern string, h http.HandlerFunc)
|
||||
Head(pattern string, h http.HandlerFunc)
|
||||
Options(pattern string, h http.HandlerFunc)
|
||||
Patch(pattern string, h http.HandlerFunc)
|
||||
Post(pattern string, h http.HandlerFunc)
|
||||
Put(pattern string, h http.HandlerFunc)
|
||||
Trace(pattern string, h http.HandlerFunc)
|
||||
|
||||
// NotFound defines a handler to respond whenever a route could
|
||||
// not be found.
|
||||
NotFound(h http.HandlerFunc)
|
||||
|
||||
// MethodNotAllowed defines a handler to respond whenever a method is
|
||||
// not allowed.
|
||||
MethodNotAllowed(h http.HandlerFunc)
|
||||
}
|
||||
|
||||
// Routes interface adds two methods for router traversal, which is also
|
||||
// used by the `docgen` subpackage to generation documentation for Routers.
|
||||
type Routes interface {
|
||||
// Routes returns the routing tree in an easily traversable structure.
|
||||
Routes() []Route
|
||||
|
||||
// Middlewares returns the list of middlewares in use by the router.
|
||||
Middlewares() Middlewares
|
||||
|
||||
// Match searches the routing tree for a handler that matches
|
||||
// the method/path - similar to routing a http request, but without
|
||||
// executing the handler thereafter.
|
||||
Match(rctx *Context, method, path string) bool
|
||||
}
|
||||
|
||||
// Middlewares type is a slice of standard middleware handlers with methods
|
||||
// to compose middleware chains and http.Handler's.
|
||||
type Middlewares []func(http.Handler) http.Handler
|
||||
157
vendor/github.com/go-chi/chi/v5/context.go
generated
vendored
Normal file
157
vendor/github.com/go-chi/chi/v5/context.go
generated
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
package chi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// URLParam returns the url parameter from a http.Request object.
|
||||
func URLParam(r *http.Request, key string) string {
|
||||
if rctx := RouteContext(r.Context()); rctx != nil {
|
||||
return rctx.URLParam(key)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// URLParamFromCtx returns the url parameter from a http.Request Context.
|
||||
func URLParamFromCtx(ctx context.Context, key string) string {
|
||||
if rctx := RouteContext(ctx); rctx != nil {
|
||||
return rctx.URLParam(key)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// RouteContext returns chi's routing Context object from a
|
||||
// http.Request Context.
|
||||
func RouteContext(ctx context.Context) *Context {
|
||||
val, _ := ctx.Value(RouteCtxKey).(*Context)
|
||||
return val
|
||||
}
|
||||
|
||||
// NewRouteContext returns a new routing Context object.
|
||||
func NewRouteContext() *Context {
|
||||
return &Context{}
|
||||
}
|
||||
|
||||
var (
|
||||
// RouteCtxKey is the context.Context key to store the request context.
|
||||
RouteCtxKey = &contextKey{"RouteContext"}
|
||||
)
|
||||
|
||||
// Context is the default routing context set on the root node of a
|
||||
// request context to track route patterns, URL parameters and
|
||||
// an optional routing path.
|
||||
type Context struct {
|
||||
Routes Routes
|
||||
|
||||
// Routing path/method override used during the route search.
|
||||
// See Mux#routeHTTP method.
|
||||
RoutePath string
|
||||
RouteMethod string
|
||||
|
||||
// Routing pattern stack throughout the lifecycle of the request,
|
||||
// across all connected routers. It is a record of all matching
|
||||
// patterns across a stack of sub-routers.
|
||||
RoutePatterns []string
|
||||
|
||||
// URLParams are the stack of routeParams captured during the
|
||||
// routing lifecycle across a stack of sub-routers.
|
||||
URLParams RouteParams
|
||||
|
||||
// The endpoint routing pattern that matched the request URI path
|
||||
// or `RoutePath` of the current sub-router. This value will update
|
||||
// during the lifecycle of a request passing through a stack of
|
||||
// sub-routers.
|
||||
routePattern string
|
||||
|
||||
// Route parameters matched for the current sub-router. It is
|
||||
// intentionally unexported so it cant be tampered.
|
||||
routeParams RouteParams
|
||||
|
||||
// methodNotAllowed hint
|
||||
methodNotAllowed bool
|
||||
|
||||
// parentCtx is the parent of this one, for using Context as a
|
||||
// context.Context directly. This is an optimization that saves
|
||||
// 1 allocation.
|
||||
parentCtx context.Context
|
||||
}
|
||||
|
||||
// Reset a routing context to its initial state.
|
||||
func (x *Context) Reset() {
|
||||
x.Routes = nil
|
||||
x.RoutePath = ""
|
||||
x.RouteMethod = ""
|
||||
x.RoutePatterns = x.RoutePatterns[:0]
|
||||
x.URLParams.Keys = x.URLParams.Keys[:0]
|
||||
x.URLParams.Values = x.URLParams.Values[:0]
|
||||
|
||||
x.routePattern = ""
|
||||
x.routeParams.Keys = x.routeParams.Keys[:0]
|
||||
x.routeParams.Values = x.routeParams.Values[:0]
|
||||
x.methodNotAllowed = false
|
||||
x.parentCtx = nil
|
||||
}
|
||||
|
||||
// URLParam returns the corresponding URL parameter value from the request
|
||||
// routing context.
|
||||
func (x *Context) URLParam(key string) string {
|
||||
for k := len(x.URLParams.Keys) - 1; k >= 0; k-- {
|
||||
if x.URLParams.Keys[k] == key {
|
||||
return x.URLParams.Values[k]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// RoutePattern builds the routing pattern string for the particular
|
||||
// request, at the particular point during routing. This means, the value
|
||||
// will change throughout the execution of a request in a router. That is
|
||||
// why its advised to only use this value after calling the next handler.
|
||||
//
|
||||
// For example,
|
||||
//
|
||||
// func Instrument(next http.Handler) http.Handler {
|
||||
// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// next.ServeHTTP(w, r)
|
||||
// routePattern := chi.RouteContext(r.Context()).RoutePattern()
|
||||
// measure(w, r, routePattern)
|
||||
// })
|
||||
// }
|
||||
func (x *Context) RoutePattern() string {
|
||||
routePattern := strings.Join(x.RoutePatterns, "")
|
||||
return replaceWildcards(routePattern)
|
||||
}
|
||||
|
||||
// replaceWildcards takes a route pattern and recursively replaces all
|
||||
// occurrences of "/*/" to "/".
|
||||
func replaceWildcards(p string) string {
|
||||
if strings.Contains(p, "/*/") {
|
||||
return replaceWildcards(strings.Replace(p, "/*/", "/", -1))
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// RouteParams is a structure to track URL routing parameters efficiently.
|
||||
type RouteParams struct {
|
||||
Keys, Values []string
|
||||
}
|
||||
|
||||
// Add will append a URL parameter to the end of the route param
|
||||
func (s *RouteParams) Add(key, value string) {
|
||||
s.Keys = append(s.Keys, key)
|
||||
s.Values = append(s.Values, value)
|
||||
}
|
||||
|
||||
// contextKey is a value for use with context.WithValue. It's used as
|
||||
// a pointer so it fits in an interface{} without allocation. This technique
|
||||
// for defining context keys was copied from Go 1.7's new use of context in net/http.
|
||||
type contextKey struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (k *contextKey) String() string {
|
||||
return "chi context value " + k.name
|
||||
}
|
||||
33
vendor/github.com/go-chi/chi/v5/middleware/basic_auth.go
generated
vendored
Normal file
33
vendor/github.com/go-chi/chi/v5/middleware/basic_auth.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// BasicAuth implements a simple middleware handler for adding basic http auth to a route.
|
||||
func BasicAuth(realm string, creds map[string]string) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
user, pass, ok := r.BasicAuth()
|
||||
if !ok {
|
||||
basicAuthFailed(w, realm)
|
||||
return
|
||||
}
|
||||
|
||||
credPass, credUserOk := creds[user]
|
||||
if !credUserOk || subtle.ConstantTimeCompare([]byte(pass), []byte(credPass)) != 1 {
|
||||
basicAuthFailed(w, realm)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func basicAuthFailed(w http.ResponseWriter, realm string) {
|
||||
w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm))
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
}
|
||||
28
vendor/github.com/go-chi/chi/v5/middleware/clean_path.go
generated
vendored
Normal file
28
vendor/github.com/go-chi/chi/v5/middleware/clean_path.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
// CleanPath middleware will clean out double slash mistakes from a user's request path.
|
||||
// For example, if a user requests /users//1 or //users////1 will both be treated as: /users/1
|
||||
func CleanPath(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
rctx := chi.RouteContext(r.Context())
|
||||
|
||||
routePath := rctx.RoutePath
|
||||
if routePath == "" {
|
||||
if r.URL.RawPath != "" {
|
||||
routePath = r.URL.RawPath
|
||||
} else {
|
||||
routePath = r.URL.Path
|
||||
}
|
||||
rctx.RoutePath = path.Clean(routePath)
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
399
vendor/github.com/go-chi/chi/v5/middleware/compress.go
generated
vendored
Normal file
399
vendor/github.com/go-chi/chi/v5/middleware/compress.go
generated
vendored
Normal file
@@ -0,0 +1,399 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"compress/flate"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var defaultCompressibleContentTypes = []string{
|
||||
"text/html",
|
||||
"text/css",
|
||||
"text/plain",
|
||||
"text/javascript",
|
||||
"application/javascript",
|
||||
"application/x-javascript",
|
||||
"application/json",
|
||||
"application/atom+xml",
|
||||
"application/rss+xml",
|
||||
"image/svg+xml",
|
||||
}
|
||||
|
||||
// Compress is a middleware that compresses response
|
||||
// body of a given content types to a data format based
|
||||
// on Accept-Encoding request header. It uses a given
|
||||
// compression level.
|
||||
//
|
||||
// NOTE: make sure to set the Content-Type header on your response
|
||||
// otherwise this middleware will not compress the response body. For ex, in
|
||||
// your handler you should set w.Header().Set("Content-Type", http.DetectContentType(yourBody))
|
||||
// or set it manually.
|
||||
//
|
||||
// Passing a compression level of 5 is sensible value
|
||||
func Compress(level int, types ...string) func(next http.Handler) http.Handler {
|
||||
compressor := NewCompressor(level, types...)
|
||||
return compressor.Handler
|
||||
}
|
||||
|
||||
// Compressor represents a set of encoding configurations.
|
||||
type Compressor struct {
|
||||
level int // The compression level.
|
||||
// The mapping of encoder names to encoder functions.
|
||||
encoders map[string]EncoderFunc
|
||||
// The mapping of pooled encoders to pools.
|
||||
pooledEncoders map[string]*sync.Pool
|
||||
// The set of content types allowed to be compressed.
|
||||
allowedTypes map[string]struct{}
|
||||
allowedWildcards map[string]struct{}
|
||||
// The list of encoders in order of decreasing precedence.
|
||||
encodingPrecedence []string
|
||||
}
|
||||
|
||||
// NewCompressor creates a new Compressor that will handle encoding responses.
|
||||
//
|
||||
// The level should be one of the ones defined in the flate package.
|
||||
// The types are the content types that are allowed to be compressed.
|
||||
func NewCompressor(level int, types ...string) *Compressor {
|
||||
// If types are provided, set those as the allowed types. If none are
|
||||
// provided, use the default list.
|
||||
allowedTypes := make(map[string]struct{})
|
||||
allowedWildcards := make(map[string]struct{})
|
||||
if len(types) > 0 {
|
||||
for _, t := range types {
|
||||
if strings.Contains(strings.TrimSuffix(t, "/*"), "*") {
|
||||
panic(fmt.Sprintf("middleware/compress: Unsupported content-type wildcard pattern '%s'. Only '/*' supported", t))
|
||||
}
|
||||
if strings.HasSuffix(t, "/*") {
|
||||
allowedWildcards[strings.TrimSuffix(t, "/*")] = struct{}{}
|
||||
} else {
|
||||
allowedTypes[t] = struct{}{}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, t := range defaultCompressibleContentTypes {
|
||||
allowedTypes[t] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
c := &Compressor{
|
||||
level: level,
|
||||
encoders: make(map[string]EncoderFunc),
|
||||
pooledEncoders: make(map[string]*sync.Pool),
|
||||
allowedTypes: allowedTypes,
|
||||
allowedWildcards: allowedWildcards,
|
||||
}
|
||||
|
||||
// Set the default encoders. The precedence order uses the reverse
|
||||
// ordering that the encoders were added. This means adding new encoders
|
||||
// will move them to the front of the order.
|
||||
//
|
||||
// TODO:
|
||||
// lzma: Opera.
|
||||
// sdch: Chrome, Android. Gzip output + dictionary header.
|
||||
// br: Brotli, see https://github.com/go-chi/chi/pull/326
|
||||
|
||||
// HTTP 1.1 "deflate" (RFC 2616) stands for DEFLATE data (RFC 1951)
|
||||
// wrapped with zlib (RFC 1950). The zlib wrapper uses Adler-32
|
||||
// checksum compared to CRC-32 used in "gzip" and thus is faster.
|
||||
//
|
||||
// But.. some old browsers (MSIE, Safari 5.1) incorrectly expect
|
||||
// raw DEFLATE data only, without the mentioned zlib wrapper.
|
||||
// Because of this major confusion, most modern browsers try it
|
||||
// both ways, first looking for zlib headers.
|
||||
// Quote by Mark Adler: http://stackoverflow.com/a/9186091/385548
|
||||
//
|
||||
// The list of browsers having problems is quite big, see:
|
||||
// http://zoompf.com/blog/2012/02/lose-the-wait-http-compression
|
||||
// https://web.archive.org/web/20120321182910/http://www.vervestudios.co/projects/compression-tests/results
|
||||
//
|
||||
// That's why we prefer gzip over deflate. It's just more reliable
|
||||
// and not significantly slower than gzip.
|
||||
c.SetEncoder("deflate", encoderDeflate)
|
||||
|
||||
// TODO: Exception for old MSIE browsers that can't handle non-HTML?
|
||||
// https://zoompf.com/blog/2012/02/lose-the-wait-http-compression
|
||||
c.SetEncoder("gzip", encoderGzip)
|
||||
|
||||
// NOTE: Not implemented, intentionally:
|
||||
// case "compress": // LZW. Deprecated.
|
||||
// case "bzip2": // Too slow on-the-fly.
|
||||
// case "zopfli": // Too slow on-the-fly.
|
||||
// case "xz": // Too slow on-the-fly.
|
||||
return c
|
||||
}
|
||||
|
||||
// SetEncoder can be used to set the implementation of a compression algorithm.
|
||||
//
|
||||
// The encoding should be a standardised identifier. See:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding
|
||||
//
|
||||
// For example, add the Brotli algortithm:
|
||||
//
|
||||
// import brotli_enc "gopkg.in/kothar/brotli-go.v0/enc"
|
||||
//
|
||||
// compressor := middleware.NewCompressor(5, "text/html")
|
||||
// compressor.SetEncoder("br", func(w http.ResponseWriter, level int) io.Writer {
|
||||
// params := brotli_enc.NewBrotliParams()
|
||||
// params.SetQuality(level)
|
||||
// return brotli_enc.NewBrotliWriter(params, w)
|
||||
// })
|
||||
func (c *Compressor) SetEncoder(encoding string, fn EncoderFunc) {
|
||||
encoding = strings.ToLower(encoding)
|
||||
if encoding == "" {
|
||||
panic("the encoding can not be empty")
|
||||
}
|
||||
if fn == nil {
|
||||
panic("attempted to set a nil encoder function")
|
||||
}
|
||||
|
||||
// If we are adding a new encoder that is already registered, we have to
|
||||
// clear that one out first.
|
||||
if _, ok := c.pooledEncoders[encoding]; ok {
|
||||
delete(c.pooledEncoders, encoding)
|
||||
}
|
||||
if _, ok := c.encoders[encoding]; ok {
|
||||
delete(c.encoders, encoding)
|
||||
}
|
||||
|
||||
// If the encoder supports Resetting (IoReseterWriter), then it can be pooled.
|
||||
encoder := fn(ioutil.Discard, c.level)
|
||||
if encoder != nil {
|
||||
if _, ok := encoder.(ioResetterWriter); ok {
|
||||
pool := &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return fn(ioutil.Discard, c.level)
|
||||
},
|
||||
}
|
||||
c.pooledEncoders[encoding] = pool
|
||||
}
|
||||
}
|
||||
// If the encoder is not in the pooledEncoders, add it to the normal encoders.
|
||||
if _, ok := c.pooledEncoders[encoding]; !ok {
|
||||
c.encoders[encoding] = fn
|
||||
}
|
||||
|
||||
for i, v := range c.encodingPrecedence {
|
||||
if v == encoding {
|
||||
c.encodingPrecedence = append(c.encodingPrecedence[:i], c.encodingPrecedence[i+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
c.encodingPrecedence = append([]string{encoding}, c.encodingPrecedence...)
|
||||
}
|
||||
|
||||
// Handler returns a new middleware that will compress the response based on the
|
||||
// current Compressor.
|
||||
func (c *Compressor) Handler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
encoder, encoding, cleanup := c.selectEncoder(r.Header, w)
|
||||
|
||||
cw := &compressResponseWriter{
|
||||
ResponseWriter: w,
|
||||
w: w,
|
||||
contentTypes: c.allowedTypes,
|
||||
contentWildcards: c.allowedWildcards,
|
||||
encoding: encoding,
|
||||
compressable: false, // determined in post-handler
|
||||
}
|
||||
if encoder != nil {
|
||||
cw.w = encoder
|
||||
}
|
||||
// Re-add the encoder to the pool if applicable.
|
||||
defer cleanup()
|
||||
defer cw.Close()
|
||||
|
||||
next.ServeHTTP(cw, r)
|
||||
})
|
||||
}
|
||||
|
||||
// selectEncoder returns the encoder, the name of the encoder, and a closer function.
|
||||
func (c *Compressor) selectEncoder(h http.Header, w io.Writer) (io.Writer, string, func()) {
|
||||
header := h.Get("Accept-Encoding")
|
||||
|
||||
// Parse the names of all accepted algorithms from the header.
|
||||
accepted := strings.Split(strings.ToLower(header), ",")
|
||||
|
||||
// Find supported encoder by accepted list by precedence
|
||||
for _, name := range c.encodingPrecedence {
|
||||
if matchAcceptEncoding(accepted, name) {
|
||||
if pool, ok := c.pooledEncoders[name]; ok {
|
||||
encoder := pool.Get().(ioResetterWriter)
|
||||
cleanup := func() {
|
||||
pool.Put(encoder)
|
||||
}
|
||||
encoder.Reset(w)
|
||||
return encoder, name, cleanup
|
||||
|
||||
}
|
||||
if fn, ok := c.encoders[name]; ok {
|
||||
return fn(w, c.level), name, func() {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// No encoder found to match the accepted encoding
|
||||
return nil, "", func() {}
|
||||
}
|
||||
|
||||
func matchAcceptEncoding(accepted []string, encoding string) bool {
|
||||
for _, v := range accepted {
|
||||
if strings.Contains(v, encoding) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// An EncoderFunc is a function that wraps the provided io.Writer with a
|
||||
// streaming compression algorithm and returns it.
|
||||
//
|
||||
// In case of failure, the function should return nil.
|
||||
type EncoderFunc func(w io.Writer, level int) io.Writer
|
||||
|
||||
// Interface for types that allow resetting io.Writers.
|
||||
type ioResetterWriter interface {
|
||||
io.Writer
|
||||
Reset(w io.Writer)
|
||||
}
|
||||
|
||||
type compressResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
|
||||
// The streaming encoder writer to be used if there is one. Otherwise,
|
||||
// this is just the normal writer.
|
||||
w io.Writer
|
||||
encoding string
|
||||
contentTypes map[string]struct{}
|
||||
contentWildcards map[string]struct{}
|
||||
wroteHeader bool
|
||||
compressable bool
|
||||
}
|
||||
|
||||
func (cw *compressResponseWriter) isCompressable() bool {
|
||||
// Parse the first part of the Content-Type response header.
|
||||
contentType := cw.Header().Get("Content-Type")
|
||||
if idx := strings.Index(contentType, ";"); idx >= 0 {
|
||||
contentType = contentType[0:idx]
|
||||
}
|
||||
|
||||
// Is the content type compressable?
|
||||
if _, ok := cw.contentTypes[contentType]; ok {
|
||||
return true
|
||||
}
|
||||
if idx := strings.Index(contentType, "/"); idx > 0 {
|
||||
contentType = contentType[0:idx]
|
||||
_, ok := cw.contentWildcards[contentType]
|
||||
return ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (cw *compressResponseWriter) WriteHeader(code int) {
|
||||
if cw.wroteHeader {
|
||||
cw.ResponseWriter.WriteHeader(code) // Allow multiple calls to propagate.
|
||||
return
|
||||
}
|
||||
cw.wroteHeader = true
|
||||
defer cw.ResponseWriter.WriteHeader(code)
|
||||
|
||||
// Already compressed data?
|
||||
if cw.Header().Get("Content-Encoding") != "" {
|
||||
return
|
||||
}
|
||||
|
||||
if !cw.isCompressable() {
|
||||
cw.compressable = false
|
||||
return
|
||||
}
|
||||
|
||||
if cw.encoding != "" {
|
||||
cw.compressable = true
|
||||
cw.Header().Set("Content-Encoding", cw.encoding)
|
||||
cw.Header().Set("Vary", "Accept-Encoding")
|
||||
|
||||
// The content-length after compression is unknown
|
||||
cw.Header().Del("Content-Length")
|
||||
}
|
||||
}
|
||||
|
||||
func (cw *compressResponseWriter) Write(p []byte) (int, error) {
|
||||
if !cw.wroteHeader {
|
||||
cw.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
return cw.writer().Write(p)
|
||||
}
|
||||
|
||||
func (cw *compressResponseWriter) writer() io.Writer {
|
||||
if cw.compressable {
|
||||
return cw.w
|
||||
} else {
|
||||
return cw.ResponseWriter
|
||||
}
|
||||
}
|
||||
|
||||
type compressFlusher interface {
|
||||
Flush() error
|
||||
}
|
||||
|
||||
func (cw *compressResponseWriter) Flush() {
|
||||
if f, ok := cw.writer().(http.Flusher); ok {
|
||||
f.Flush()
|
||||
}
|
||||
// If the underlying writer has a compression flush signature,
|
||||
// call this Flush() method instead
|
||||
if f, ok := cw.writer().(compressFlusher); ok {
|
||||
f.Flush()
|
||||
|
||||
// Also flush the underlying response writer
|
||||
if f, ok := cw.ResponseWriter.(http.Flusher); ok {
|
||||
f.Flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (cw *compressResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
if hj, ok := cw.writer().(http.Hijacker); ok {
|
||||
return hj.Hijack()
|
||||
}
|
||||
return nil, nil, errors.New("chi/middleware: http.Hijacker is unavailable on the writer")
|
||||
}
|
||||
|
||||
func (cw *compressResponseWriter) Push(target string, opts *http.PushOptions) error {
|
||||
if ps, ok := cw.writer().(http.Pusher); ok {
|
||||
return ps.Push(target, opts)
|
||||
}
|
||||
return errors.New("chi/middleware: http.Pusher is unavailable on the writer")
|
||||
}
|
||||
|
||||
func (cw *compressResponseWriter) Close() error {
|
||||
if c, ok := cw.writer().(io.WriteCloser); ok {
|
||||
return c.Close()
|
||||
}
|
||||
return errors.New("chi/middleware: io.WriteCloser is unavailable on the writer")
|
||||
}
|
||||
|
||||
func encoderGzip(w io.Writer, level int) io.Writer {
|
||||
gw, err := gzip.NewWriterLevel(w, level)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return gw
|
||||
}
|
||||
|
||||
func encoderDeflate(w io.Writer, level int) io.Writer {
|
||||
dw, err := flate.NewWriter(w, level)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return dw
|
||||
}
|
||||
51
vendor/github.com/go-chi/chi/v5/middleware/content_charset.go
generated
vendored
Normal file
51
vendor/github.com/go-chi/chi/v5/middleware/content_charset.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ContentCharset generates a handler that writes a 415 Unsupported Media Type response if none of the charsets match.
|
||||
// An empty charset will allow requests with no Content-Type header or no specified charset.
|
||||
func ContentCharset(charsets ...string) func(next http.Handler) http.Handler {
|
||||
for i, c := range charsets {
|
||||
charsets[i] = strings.ToLower(c)
|
||||
}
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !contentEncoding(r.Header.Get("Content-Type"), charsets...) {
|
||||
w.WriteHeader(http.StatusUnsupportedMediaType)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Check the content encoding against a list of acceptable values.
|
||||
func contentEncoding(ce string, charsets ...string) bool {
|
||||
_, ce = split(strings.ToLower(ce), ";")
|
||||
_, ce = split(ce, "charset=")
|
||||
ce, _ = split(ce, ";")
|
||||
for _, c := range charsets {
|
||||
if ce == c {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Split a string in two parts, cleaning any whitespace.
|
||||
func split(str, sep string) (string, string) {
|
||||
var a, b string
|
||||
var parts = strings.SplitN(str, sep, 2)
|
||||
a = strings.TrimSpace(parts[0])
|
||||
if len(parts) == 2 {
|
||||
b = strings.TrimSpace(parts[1])
|
||||
}
|
||||
|
||||
return a, b
|
||||
}
|
||||
34
vendor/github.com/go-chi/chi/v5/middleware/content_encoding.go
generated
vendored
Normal file
34
vendor/github.com/go-chi/chi/v5/middleware/content_encoding.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AllowContentEncoding enforces a whitelist of request Content-Encoding otherwise responds
|
||||
// with a 415 Unsupported Media Type status.
|
||||
func AllowContentEncoding(contentEncoding ...string) func(next http.Handler) http.Handler {
|
||||
allowedEncodings := make(map[string]struct{}, len(contentEncoding))
|
||||
for _, encoding := range contentEncoding {
|
||||
allowedEncodings[strings.TrimSpace(strings.ToLower(encoding))] = struct{}{}
|
||||
}
|
||||
return func(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
requestEncodings := r.Header["Content-Encoding"]
|
||||
// skip check for empty content body or no Content-Encoding
|
||||
if r.ContentLength == 0 {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
// All encodings in the request must be allowed
|
||||
for _, encoding := range requestEncodings {
|
||||
if _, ok := allowedEncodings[strings.TrimSpace(strings.ToLower(encoding))]; !ok {
|
||||
w.WriteHeader(http.StatusUnsupportedMediaType)
|
||||
return
|
||||
}
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
}
|
||||
49
vendor/github.com/go-chi/chi/v5/middleware/content_type.go
generated
vendored
Normal file
49
vendor/github.com/go-chi/chi/v5/middleware/content_type.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SetHeader is a convenience handler to set a response header key/value
|
||||
func SetHeader(key, value string) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set(key, value)
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
}
|
||||
|
||||
// AllowContentType enforces a whitelist of request Content-Types otherwise responds
|
||||
// with a 415 Unsupported Media Type status.
|
||||
func AllowContentType(contentTypes ...string) func(next http.Handler) http.Handler {
|
||||
allowedContentTypes := make(map[string]struct{}, len(contentTypes))
|
||||
for _, ctype := range contentTypes {
|
||||
allowedContentTypes[strings.TrimSpace(strings.ToLower(ctype))] = struct{}{}
|
||||
}
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.ContentLength == 0 {
|
||||
// skip check for empty content body
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
s := strings.ToLower(strings.TrimSpace(r.Header.Get("Content-Type")))
|
||||
if i := strings.Index(s, ";"); i > -1 {
|
||||
s = s[0:i]
|
||||
}
|
||||
|
||||
if _, ok := allowedContentTypes[s]; ok {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusUnsupportedMediaType)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
}
|
||||
39
vendor/github.com/go-chi/chi/v5/middleware/get_head.go
generated
vendored
Normal file
39
vendor/github.com/go-chi/chi/v5/middleware/get_head.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
// GetHead automatically route undefined HEAD requests to GET handlers.
|
||||
func GetHead(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "HEAD" {
|
||||
rctx := chi.RouteContext(r.Context())
|
||||
routePath := rctx.RoutePath
|
||||
if routePath == "" {
|
||||
if r.URL.RawPath != "" {
|
||||
routePath = r.URL.RawPath
|
||||
} else {
|
||||
routePath = r.URL.Path
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary routing context to look-ahead before routing the request
|
||||
tctx := chi.NewRouteContext()
|
||||
|
||||
// Attempt to find a HEAD handler for the routing path, if not found, traverse
|
||||
// the router as through its a GET route, but proceed with the request
|
||||
// with the HEAD method.
|
||||
if !rctx.Routes.Match(tctx, "HEAD", routePath) {
|
||||
rctx.RouteMethod = "GET"
|
||||
rctx.RoutePath = routePath
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
26
vendor/github.com/go-chi/chi/v5/middleware/heartbeat.go
generated
vendored
Normal file
26
vendor/github.com/go-chi/chi/v5/middleware/heartbeat.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Heartbeat endpoint middleware useful to setting up a path like
|
||||
// `/ping` that load balancers or uptime testing external services
|
||||
// can make a request before hitting any routes. It's also convenient
|
||||
// to place this above ACL middlewares as well.
|
||||
func Heartbeat(endpoint string) func(http.Handler) http.Handler {
|
||||
f := func(h http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "GET" && strings.EqualFold(r.URL.Path, endpoint) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("."))
|
||||
return
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
return f
|
||||
}
|
||||
174
vendor/github.com/go-chi/chi/v5/middleware/logger.go
generated
vendored
Normal file
174
vendor/github.com/go-chi/chi/v5/middleware/logger.go
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// LogEntryCtxKey is the context.Context key to store the request log entry.
|
||||
LogEntryCtxKey = &contextKey{"LogEntry"}
|
||||
|
||||
// DefaultLogger is called by the Logger middleware handler to log each request.
|
||||
// Its made a package-level variable so that it can be reconfigured for custom
|
||||
// logging configurations.
|
||||
DefaultLogger func(next http.Handler) http.Handler
|
||||
)
|
||||
|
||||
// Logger is a middleware that logs the start and end of each request, along
|
||||
// with some useful data about what was requested, what the response status was,
|
||||
// and how long it took to return. When standard output is a TTY, Logger will
|
||||
// print in color, otherwise it will print in black and white. Logger prints a
|
||||
// request ID if one is provided.
|
||||
//
|
||||
// Alternatively, look at https://github.com/goware/httplog for a more in-depth
|
||||
// http logger with structured logging support.
|
||||
//
|
||||
// IMPORTANT NOTE: Logger should go before any other middleware that may change
|
||||
// the response, such as `middleware.Recoverer`. Example:
|
||||
//
|
||||
// ```go
|
||||
// r := chi.NewRouter()
|
||||
// r.Use(middleware.Logger) // <--<< Logger should come before Recoverer
|
||||
// r.Use(middleware.Recoverer)
|
||||
// r.Get("/", handler)
|
||||
// ```
|
||||
func Logger(next http.Handler) http.Handler {
|
||||
return DefaultLogger(next)
|
||||
}
|
||||
|
||||
// RequestLogger returns a logger handler using a custom LogFormatter.
|
||||
func RequestLogger(f LogFormatter) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
entry := f.NewLogEntry(r)
|
||||
ww := NewWrapResponseWriter(w, r.ProtoMajor)
|
||||
|
||||
t1 := time.Now()
|
||||
defer func() {
|
||||
entry.Write(ww.Status(), ww.BytesWritten(), ww.Header(), time.Since(t1), nil)
|
||||
}()
|
||||
|
||||
next.ServeHTTP(ww, WithLogEntry(r, entry))
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
}
|
||||
|
||||
// LogFormatter initiates the beginning of a new LogEntry per request.
|
||||
// See DefaultLogFormatter for an example implementation.
|
||||
type LogFormatter interface {
|
||||
NewLogEntry(r *http.Request) LogEntry
|
||||
}
|
||||
|
||||
// LogEntry records the final log when a request completes.
|
||||
// See defaultLogEntry for an example implementation.
|
||||
type LogEntry interface {
|
||||
Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{})
|
||||
Panic(v interface{}, stack []byte)
|
||||
}
|
||||
|
||||
// GetLogEntry returns the in-context LogEntry for a request.
|
||||
func GetLogEntry(r *http.Request) LogEntry {
|
||||
entry, _ := r.Context().Value(LogEntryCtxKey).(LogEntry)
|
||||
return entry
|
||||
}
|
||||
|
||||
// WithLogEntry sets the in-context LogEntry for a request.
|
||||
func WithLogEntry(r *http.Request, entry LogEntry) *http.Request {
|
||||
r = r.WithContext(context.WithValue(r.Context(), LogEntryCtxKey, entry))
|
||||
return r
|
||||
}
|
||||
|
||||
// LoggerInterface accepts printing to stdlib logger or compatible logger.
|
||||
type LoggerInterface interface {
|
||||
Print(v ...interface{})
|
||||
}
|
||||
|
||||
// DefaultLogFormatter is a simple logger that implements a LogFormatter.
|
||||
type DefaultLogFormatter struct {
|
||||
Logger LoggerInterface
|
||||
NoColor bool
|
||||
}
|
||||
|
||||
// NewLogEntry creates a new LogEntry for the request.
|
||||
func (l *DefaultLogFormatter) NewLogEntry(r *http.Request) LogEntry {
|
||||
useColor := !l.NoColor
|
||||
entry := &defaultLogEntry{
|
||||
DefaultLogFormatter: l,
|
||||
request: r,
|
||||
buf: &bytes.Buffer{},
|
||||
useColor: useColor,
|
||||
}
|
||||
|
||||
reqID := GetReqID(r.Context())
|
||||
if reqID != "" {
|
||||
cW(entry.buf, useColor, nYellow, "[%s] ", reqID)
|
||||
}
|
||||
cW(entry.buf, useColor, nCyan, "\"")
|
||||
cW(entry.buf, useColor, bMagenta, "%s ", r.Method)
|
||||
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
cW(entry.buf, useColor, nCyan, "%s://%s%s %s\" ", scheme, r.Host, r.RequestURI, r.Proto)
|
||||
|
||||
entry.buf.WriteString("from ")
|
||||
entry.buf.WriteString(r.RemoteAddr)
|
||||
entry.buf.WriteString(" - ")
|
||||
|
||||
return entry
|
||||
}
|
||||
|
||||
type defaultLogEntry struct {
|
||||
*DefaultLogFormatter
|
||||
request *http.Request
|
||||
buf *bytes.Buffer
|
||||
useColor bool
|
||||
}
|
||||
|
||||
func (l *defaultLogEntry) Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{}) {
|
||||
switch {
|
||||
case status < 200:
|
||||
cW(l.buf, l.useColor, bBlue, "%03d", status)
|
||||
case status < 300:
|
||||
cW(l.buf, l.useColor, bGreen, "%03d", status)
|
||||
case status < 400:
|
||||
cW(l.buf, l.useColor, bCyan, "%03d", status)
|
||||
case status < 500:
|
||||
cW(l.buf, l.useColor, bYellow, "%03d", status)
|
||||
default:
|
||||
cW(l.buf, l.useColor, bRed, "%03d", status)
|
||||
}
|
||||
|
||||
cW(l.buf, l.useColor, bBlue, " %dB", bytes)
|
||||
|
||||
l.buf.WriteString(" in ")
|
||||
if elapsed < 500*time.Millisecond {
|
||||
cW(l.buf, l.useColor, nGreen, "%s", elapsed)
|
||||
} else if elapsed < 5*time.Second {
|
||||
cW(l.buf, l.useColor, nYellow, "%s", elapsed)
|
||||
} else {
|
||||
cW(l.buf, l.useColor, nRed, "%s", elapsed)
|
||||
}
|
||||
|
||||
l.Logger.Print(l.buf.String())
|
||||
}
|
||||
|
||||
func (l *defaultLogEntry) Panic(v interface{}, stack []byte) {
|
||||
PrintPrettyStack(v)
|
||||
}
|
||||
|
||||
func init() {
|
||||
color := true
|
||||
if runtime.GOOS == "windows" {
|
||||
color = false
|
||||
}
|
||||
DefaultLogger = RequestLogger(&DefaultLogFormatter{Logger: log.New(os.Stdout, "", log.LstdFlags), NoColor: !color})
|
||||
}
|
||||
23
vendor/github.com/go-chi/chi/v5/middleware/middleware.go
generated
vendored
Normal file
23
vendor/github.com/go-chi/chi/v5/middleware/middleware.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package middleware
|
||||
|
||||
import "net/http"
|
||||
|
||||
// New will create a new middleware handler from a http.Handler.
|
||||
func New(h http.Handler) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// contextKey is a value for use with context.WithValue. It's used as
|
||||
// a pointer so it fits in an interface{} without allocation. This technique
|
||||
// for defining context keys was copied from Go 1.7's new use of context in net/http.
|
||||
type contextKey struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (k *contextKey) String() string {
|
||||
return "chi/middleware context value " + k.name
|
||||
}
|
||||
58
vendor/github.com/go-chi/chi/v5/middleware/nocache.go
generated
vendored
Normal file
58
vendor/github.com/go-chi/chi/v5/middleware/nocache.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package middleware
|
||||
|
||||
// Ported from Goji's middleware, source:
|
||||
// https://github.com/zenazn/goji/tree/master/web/middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Unix epoch time
|
||||
var epoch = time.Unix(0, 0).Format(time.RFC1123)
|
||||
|
||||
// Taken from https://github.com/mytrile/nocache
|
||||
var noCacheHeaders = map[string]string{
|
||||
"Expires": epoch,
|
||||
"Cache-Control": "no-cache, no-store, no-transform, must-revalidate, private, max-age=0",
|
||||
"Pragma": "no-cache",
|
||||
"X-Accel-Expires": "0",
|
||||
}
|
||||
|
||||
var etagHeaders = []string{
|
||||
"ETag",
|
||||
"If-Modified-Since",
|
||||
"If-Match",
|
||||
"If-None-Match",
|
||||
"If-Range",
|
||||
"If-Unmodified-Since",
|
||||
}
|
||||
|
||||
// NoCache is a simple piece of middleware that sets a number of HTTP headers to prevent
|
||||
// a router (or subrouter) from being cached by an upstream proxy and/or client.
|
||||
//
|
||||
// As per http://wiki.nginx.org/HttpProxyModule - NoCache sets:
|
||||
// Expires: Thu, 01 Jan 1970 00:00:00 UTC
|
||||
// Cache-Control: no-cache, private, max-age=0
|
||||
// X-Accel-Expires: 0
|
||||
// Pragma: no-cache (for HTTP/1.0 proxies/clients)
|
||||
func NoCache(h http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Delete any ETag headers that may have been set
|
||||
for _, v := range etagHeaders {
|
||||
if r.Header.Get(v) != "" {
|
||||
r.Header.Del(v)
|
||||
}
|
||||
}
|
||||
|
||||
// Set our NoCache headers
|
||||
for k, v := range noCacheHeaders {
|
||||
w.Header().Set(k, v)
|
||||
}
|
||||
|
||||
h.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
55
vendor/github.com/go-chi/chi/v5/middleware/profiler.go
generated
vendored
Normal file
55
vendor/github.com/go-chi/chi/v5/middleware/profiler.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
// Profiler is a convenient subrouter used for mounting net/http/pprof. ie.
|
||||
//
|
||||
// func MyService() http.Handler {
|
||||
// r := chi.NewRouter()
|
||||
// // ..middlewares
|
||||
// r.Mount("/debug", middleware.Profiler())
|
||||
// // ..routes
|
||||
// return r
|
||||
// }
|
||||
func Profiler() http.Handler {
|
||||
r := chi.NewRouter()
|
||||
r.Use(NoCache)
|
||||
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, r.RequestURI+"/pprof/", http.StatusMovedPermanently)
|
||||
})
|
||||
r.HandleFunc("/pprof", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, r.RequestURI+"/", http.StatusMovedPermanently)
|
||||
})
|
||||
|
||||
r.HandleFunc("/pprof/*", pprof.Index)
|
||||
r.HandleFunc("/pprof/cmdline", pprof.Cmdline)
|
||||
r.HandleFunc("/pprof/profile", pprof.Profile)
|
||||
r.HandleFunc("/pprof/symbol", pprof.Symbol)
|
||||
r.HandleFunc("/pprof/trace", pprof.Trace)
|
||||
r.HandleFunc("/vars", expVars)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Replicated from expvar.go as not public.
|
||||
func expVars(w http.ResponseWriter, r *http.Request) {
|
||||
first := true
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, "{\n")
|
||||
expvar.Do(func(kv expvar.KeyValue) {
|
||||
if !first {
|
||||
fmt.Fprintf(w, ",\n")
|
||||
}
|
||||
first = false
|
||||
fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
|
||||
})
|
||||
fmt.Fprintf(w, "\n}\n")
|
||||
}
|
||||
54
vendor/github.com/go-chi/chi/v5/middleware/realip.go
generated
vendored
Normal file
54
vendor/github.com/go-chi/chi/v5/middleware/realip.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
package middleware
|
||||
|
||||
// Ported from Goji's middleware, source:
|
||||
// https://github.com/zenazn/goji/tree/master/web/middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
|
||||
var xRealIP = http.CanonicalHeaderKey("X-Real-IP")
|
||||
|
||||
// RealIP is a middleware that sets a http.Request's RemoteAddr to the results
|
||||
// of parsing either the X-Forwarded-For header or the X-Real-IP header (in that
|
||||
// order).
|
||||
//
|
||||
// This middleware should be inserted fairly early in the middleware stack to
|
||||
// ensure that subsequent layers (e.g., request loggers) which examine the
|
||||
// RemoteAddr will see the intended value.
|
||||
//
|
||||
// You should only use this middleware if you can trust the headers passed to
|
||||
// you (in particular, the two headers this middleware uses), for example
|
||||
// because you have placed a reverse proxy like HAProxy or nginx in front of
|
||||
// chi. If your reverse proxies are configured to pass along arbitrary header
|
||||
// values from the client, or if you use this middleware without a reverse
|
||||
// proxy, malicious clients will be able to make you very sad (or, depending on
|
||||
// how you're using RemoteAddr, vulnerable to an attack of some sort).
|
||||
func RealIP(h http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
if rip := realIP(r); rip != "" {
|
||||
r.RemoteAddr = rip
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
func realIP(r *http.Request) string {
|
||||
var ip string
|
||||
|
||||
if xrip := r.Header.Get(xRealIP); xrip != "" {
|
||||
ip = xrip
|
||||
} else if xff := r.Header.Get(xForwardedFor); xff != "" {
|
||||
i := strings.Index(xff, ", ")
|
||||
if i == -1 {
|
||||
i = len(xff)
|
||||
}
|
||||
ip = xff[:i]
|
||||
}
|
||||
|
||||
return ip
|
||||
}
|
||||
192
vendor/github.com/go-chi/chi/v5/middleware/recoverer.go
generated
vendored
Normal file
192
vendor/github.com/go-chi/chi/v5/middleware/recoverer.go
generated
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
package middleware
|
||||
|
||||
// The original work was derived from Goji's middleware, source:
|
||||
// https://github.com/zenazn/goji/tree/master/web/middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Recoverer is a middleware that recovers from panics, logs the panic (and a
|
||||
// backtrace), and returns a HTTP 500 (Internal Server Error) status if
|
||||
// possible. Recoverer prints a request ID if one is provided.
|
||||
//
|
||||
// Alternatively, look at https://github.com/pressly/lg middleware pkgs.
|
||||
func Recoverer(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if rvr := recover(); rvr != nil && rvr != http.ErrAbortHandler {
|
||||
|
||||
logEntry := GetLogEntry(r)
|
||||
if logEntry != nil {
|
||||
logEntry.Panic(rvr, debug.Stack())
|
||||
} else {
|
||||
PrintPrettyStack(rvr)
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}()
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
func PrintPrettyStack(rvr interface{}) {
|
||||
debugStack := debug.Stack()
|
||||
s := prettyStack{}
|
||||
out, err := s.parse(debugStack, rvr)
|
||||
if err == nil {
|
||||
os.Stderr.Write(out)
|
||||
} else {
|
||||
// print stdlib output as a fallback
|
||||
os.Stderr.Write(debugStack)
|
||||
}
|
||||
}
|
||||
|
||||
type prettyStack struct {
|
||||
}
|
||||
|
||||
func (s prettyStack) parse(debugStack []byte, rvr interface{}) ([]byte, error) {
|
||||
var err error
|
||||
useColor := true
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
cW(buf, false, bRed, "\n")
|
||||
cW(buf, useColor, bCyan, " panic: ")
|
||||
cW(buf, useColor, bBlue, "%v", rvr)
|
||||
cW(buf, false, bWhite, "\n \n")
|
||||
|
||||
// process debug stack info
|
||||
stack := strings.Split(string(debugStack), "\n")
|
||||
lines := []string{}
|
||||
|
||||
// locate panic line, as we may have nested panics
|
||||
for i := len(stack) - 1; i > 0; i-- {
|
||||
lines = append(lines, stack[i])
|
||||
if strings.HasPrefix(stack[i], "panic(0x") {
|
||||
lines = lines[0 : len(lines)-2] // remove boilerplate
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// reverse
|
||||
for i := len(lines)/2 - 1; i >= 0; i-- {
|
||||
opp := len(lines) - 1 - i
|
||||
lines[i], lines[opp] = lines[opp], lines[i]
|
||||
}
|
||||
|
||||
// decorate
|
||||
for i, line := range lines {
|
||||
lines[i], err = s.decorateLine(line, useColor, i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, l := range lines {
|
||||
fmt.Fprintf(buf, "%s", l)
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (s prettyStack) decorateLine(line string, useColor bool, num int) (string, error) {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.HasPrefix(line, "\t") || strings.Contains(line, ".go:") {
|
||||
return s.decorateSourceLine(line, useColor, num)
|
||||
} else if strings.HasSuffix(line, ")") {
|
||||
return s.decorateFuncCallLine(line, useColor, num)
|
||||
} else {
|
||||
if strings.HasPrefix(line, "\t") {
|
||||
return strings.Replace(line, "\t", " ", 1), nil
|
||||
} else {
|
||||
return fmt.Sprintf(" %s\n", line), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s prettyStack) decorateFuncCallLine(line string, useColor bool, num int) (string, error) {
|
||||
idx := strings.LastIndex(line, "(")
|
||||
if idx < 0 {
|
||||
return "", errors.New("not a func call line")
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
pkg := line[0:idx]
|
||||
// addr := line[idx:]
|
||||
method := ""
|
||||
|
||||
idx = strings.LastIndex(pkg, string(os.PathSeparator))
|
||||
if idx < 0 {
|
||||
idx = strings.Index(pkg, ".")
|
||||
method = pkg[idx:]
|
||||
pkg = pkg[0:idx]
|
||||
} else {
|
||||
method = pkg[idx+1:]
|
||||
pkg = pkg[0 : idx+1]
|
||||
idx = strings.Index(method, ".")
|
||||
pkg += method[0:idx]
|
||||
method = method[idx:]
|
||||
}
|
||||
pkgColor := nYellow
|
||||
methodColor := bGreen
|
||||
|
||||
if num == 0 {
|
||||
cW(buf, useColor, bRed, " -> ")
|
||||
pkgColor = bMagenta
|
||||
methodColor = bRed
|
||||
} else {
|
||||
cW(buf, useColor, bWhite, " ")
|
||||
}
|
||||
cW(buf, useColor, pkgColor, "%s", pkg)
|
||||
cW(buf, useColor, methodColor, "%s\n", method)
|
||||
// cW(buf, useColor, nBlack, "%s", addr)
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func (s prettyStack) decorateSourceLine(line string, useColor bool, num int) (string, error) {
|
||||
idx := strings.LastIndex(line, ".go:")
|
||||
if idx < 0 {
|
||||
return "", errors.New("not a source line")
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
path := line[0 : idx+3]
|
||||
lineno := line[idx+3:]
|
||||
|
||||
idx = strings.LastIndex(path, string(os.PathSeparator))
|
||||
dir := path[0 : idx+1]
|
||||
file := path[idx+1:]
|
||||
|
||||
idx = strings.Index(lineno, " ")
|
||||
if idx > 0 {
|
||||
lineno = lineno[0:idx]
|
||||
}
|
||||
fileColor := bCyan
|
||||
lineColor := bGreen
|
||||
|
||||
if num == 1 {
|
||||
cW(buf, useColor, bRed, " -> ")
|
||||
fileColor = bRed
|
||||
lineColor = bMagenta
|
||||
} else {
|
||||
cW(buf, false, bWhite, " ")
|
||||
}
|
||||
cW(buf, useColor, bWhite, "%s", dir)
|
||||
cW(buf, useColor, fileColor, "%s", file)
|
||||
cW(buf, useColor, lineColor, "%s", lineno)
|
||||
if num == 1 {
|
||||
cW(buf, false, bWhite, "\n")
|
||||
}
|
||||
cW(buf, false, bWhite, "\n")
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
96
vendor/github.com/go-chi/chi/v5/middleware/request_id.go
generated
vendored
Normal file
96
vendor/github.com/go-chi/chi/v5/middleware/request_id.go
generated
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
package middleware
|
||||
|
||||
// Ported from Goji's middleware, source:
|
||||
// https://github.com/zenazn/goji/tree/master/web/middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Key to use when setting the request ID.
|
||||
type ctxKeyRequestID int
|
||||
|
||||
// RequestIDKey is the key that holds the unique request ID in a request context.
|
||||
const RequestIDKey ctxKeyRequestID = 0
|
||||
|
||||
// RequestIDHeader is the name of the HTTP Header which contains the request id.
|
||||
// Exported so that it can be changed by developers
|
||||
var RequestIDHeader = "X-Request-Id"
|
||||
|
||||
var prefix string
|
||||
var reqid uint64
|
||||
|
||||
// A quick note on the statistics here: we're trying to calculate the chance that
|
||||
// two randomly generated base62 prefixes will collide. We use the formula from
|
||||
// http://en.wikipedia.org/wiki/Birthday_problem
|
||||
//
|
||||
// P[m, n] \approx 1 - e^{-m^2/2n}
|
||||
//
|
||||
// We ballpark an upper bound for $m$ by imagining (for whatever reason) a server
|
||||
// that restarts every second over 10 years, for $m = 86400 * 365 * 10 = 315360000$
|
||||
//
|
||||
// For a $k$ character base-62 identifier, we have $n(k) = 62^k$
|
||||
//
|
||||
// Plugging this in, we find $P[m, n(10)] \approx 5.75%$, which is good enough for
|
||||
// our purposes, and is surely more than anyone would ever need in practice -- a
|
||||
// process that is rebooted a handful of times a day for a hundred years has less
|
||||
// than a millionth of a percent chance of generating two colliding IDs.
|
||||
|
||||
func init() {
|
||||
hostname, err := os.Hostname()
|
||||
if hostname == "" || err != nil {
|
||||
hostname = "localhost"
|
||||
}
|
||||
var buf [12]byte
|
||||
var b64 string
|
||||
for len(b64) < 10 {
|
||||
rand.Read(buf[:])
|
||||
b64 = base64.StdEncoding.EncodeToString(buf[:])
|
||||
b64 = strings.NewReplacer("+", "", "/", "").Replace(b64)
|
||||
}
|
||||
|
||||
prefix = fmt.Sprintf("%s/%s", hostname, b64[0:10])
|
||||
}
|
||||
|
||||
// RequestID is a middleware that injects a request ID into the context of each
|
||||
// request. A request ID is a string of the form "host.example.com/random-0001",
|
||||
// where "random" is a base62 random string that uniquely identifies this go
|
||||
// process, and where the last number is an atomically incremented request
|
||||
// counter.
|
||||
func RequestID(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
requestID := r.Header.Get(RequestIDHeader)
|
||||
if requestID == "" {
|
||||
myid := atomic.AddUint64(&reqid, 1)
|
||||
requestID = fmt.Sprintf("%s-%06d", prefix, myid)
|
||||
}
|
||||
ctx = context.WithValue(ctx, RequestIDKey, requestID)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
// GetReqID returns a request ID from the given context if one is present.
|
||||
// Returns the empty string if a request ID cannot be found.
|
||||
func GetReqID(ctx context.Context) string {
|
||||
if ctx == nil {
|
||||
return ""
|
||||
}
|
||||
if reqID, ok := ctx.Value(RequestIDKey).(string); ok {
|
||||
return reqID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// NextRequestID generates the next request ID in the sequence.
|
||||
func NextRequestID() uint64 {
|
||||
return atomic.AddUint64(&reqid, 1)
|
||||
}
|
||||
160
vendor/github.com/go-chi/chi/v5/middleware/route_headers.go
generated
vendored
Normal file
160
vendor/github.com/go-chi/chi/v5/middleware/route_headers.go
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RouteHeaders is a neat little header-based router that allows you to direct
|
||||
// the flow of a request through a middleware stack based on a request header.
|
||||
//
|
||||
// For example, lets say you'd like to setup multiple routers depending on the
|
||||
// request Host header, you could then do something as so:
|
||||
//
|
||||
// r := chi.NewRouter()
|
||||
// rSubdomain := chi.NewRouter()
|
||||
//
|
||||
// r.Use(middleware.RouteHeaders().
|
||||
// Route("Host", "example.com", middleware.New(r)).
|
||||
// Route("Host", "*.example.com", middleware.New(rSubdomain)).
|
||||
// Handler)
|
||||
//
|
||||
// r.Get("/", h)
|
||||
// rSubdomain.Get("/", h2)
|
||||
//
|
||||
//
|
||||
// Another example, imagine you want to setup multiple CORS handlers, where for
|
||||
// your origin servers you allow authorized requests, but for third-party public
|
||||
// requests, authorization is disabled.
|
||||
//
|
||||
// r := chi.NewRouter()
|
||||
//
|
||||
// r.Use(middleware.RouteHeaders().
|
||||
// Route("Origin", "https://app.skyweaver.net", cors.Handler(cors.Options{
|
||||
// AllowedOrigins: []string{"https://api.skyweaver.net"},
|
||||
// AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||||
// AllowedHeaders: []string{"Accept", "Authorization", "Content-Type"},
|
||||
// AllowCredentials: true, // <----------<<< allow credentials
|
||||
// })).
|
||||
// Route("Origin", "*", cors.Handler(cors.Options{
|
||||
// AllowedOrigins: []string{"*"},
|
||||
// AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
|
||||
// AllowedHeaders: []string{"Accept", "Content-Type"},
|
||||
// AllowCredentials: false, // <----------<<< do not allow credentials
|
||||
// })).
|
||||
// Handler)
|
||||
//
|
||||
func RouteHeaders() HeaderRouter {
|
||||
return HeaderRouter{}
|
||||
}
|
||||
|
||||
type HeaderRouter map[string][]HeaderRoute
|
||||
|
||||
func (hr HeaderRouter) Route(header, match string, middlewareHandler func(next http.Handler) http.Handler) HeaderRouter {
|
||||
header = strings.ToLower(header)
|
||||
k := hr[header]
|
||||
if k == nil {
|
||||
hr[header] = []HeaderRoute{}
|
||||
}
|
||||
hr[header] = append(hr[header], HeaderRoute{MatchOne: NewPattern(match), Middleware: middlewareHandler})
|
||||
return hr
|
||||
}
|
||||
|
||||
func (hr HeaderRouter) RouteAny(header string, match []string, middlewareHandler func(next http.Handler) http.Handler) HeaderRouter {
|
||||
header = strings.ToLower(header)
|
||||
k := hr[header]
|
||||
if k == nil {
|
||||
hr[header] = []HeaderRoute{}
|
||||
}
|
||||
patterns := []Pattern{}
|
||||
for _, m := range match {
|
||||
patterns = append(patterns, NewPattern(m))
|
||||
}
|
||||
hr[header] = append(hr[header], HeaderRoute{MatchAny: patterns, Middleware: middlewareHandler})
|
||||
return hr
|
||||
}
|
||||
|
||||
func (hr HeaderRouter) RouteDefault(handler func(next http.Handler) http.Handler) HeaderRouter {
|
||||
hr["*"] = []HeaderRoute{{Middleware: handler}}
|
||||
return hr
|
||||
}
|
||||
|
||||
func (hr HeaderRouter) Handler(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if len(hr) == 0 {
|
||||
// skip if no routes set
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// find first matching header route, and continue
|
||||
for header, matchers := range hr {
|
||||
headerValue := r.Header.Get(header)
|
||||
if headerValue == "" {
|
||||
continue
|
||||
}
|
||||
headerValue = strings.ToLower(headerValue)
|
||||
for _, matcher := range matchers {
|
||||
if matcher.IsMatch(headerValue) {
|
||||
matcher.Middleware(next).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if no match, check for "*" default route
|
||||
matcher, ok := hr["*"]
|
||||
if !ok || matcher[0].Middleware == nil {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
matcher[0].Middleware(next).ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
type HeaderRoute struct {
|
||||
MatchAny []Pattern
|
||||
MatchOne Pattern
|
||||
Middleware func(next http.Handler) http.Handler
|
||||
}
|
||||
|
||||
func (r HeaderRoute) IsMatch(value string) bool {
|
||||
if len(r.MatchAny) > 0 {
|
||||
for _, m := range r.MatchAny {
|
||||
if m.Match(value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else if r.MatchOne.Match(value) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Pattern struct {
|
||||
prefix string
|
||||
suffix string
|
||||
wildcard bool
|
||||
}
|
||||
|
||||
func NewPattern(value string) Pattern {
|
||||
p := Pattern{}
|
||||
if i := strings.IndexByte(value, '*'); i >= 0 {
|
||||
p.wildcard = true
|
||||
p.prefix = value[0:i]
|
||||
p.suffix = value[i+1:]
|
||||
} else {
|
||||
p.prefix = value
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p Pattern) Match(v string) bool {
|
||||
if !p.wildcard {
|
||||
if p.prefix == v {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return len(v) >= len(p.prefix+p.suffix) && strings.HasPrefix(v, p.prefix) && strings.HasSuffix(v, p.suffix)
|
||||
}
|
||||
62
vendor/github.com/go-chi/chi/v5/middleware/strip.go
generated
vendored
Normal file
62
vendor/github.com/go-chi/chi/v5/middleware/strip.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
// StripSlashes is a middleware that will match request paths with a trailing
|
||||
// slash, strip it from the path and continue routing through the mux, if a route
|
||||
// matches, then it will serve the handler.
|
||||
func StripSlashes(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
var path string
|
||||
rctx := chi.RouteContext(r.Context())
|
||||
if rctx != nil && rctx.RoutePath != "" {
|
||||
path = rctx.RoutePath
|
||||
} else {
|
||||
path = r.URL.Path
|
||||
}
|
||||
if len(path) > 1 && path[len(path)-1] == '/' {
|
||||
newPath := path[:len(path)-1]
|
||||
if rctx == nil {
|
||||
r.URL.Path = newPath
|
||||
} else {
|
||||
rctx.RoutePath = newPath
|
||||
}
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
// RedirectSlashes is a middleware that will match request paths with a trailing
|
||||
// slash and redirect to the same path, less the trailing slash.
|
||||
//
|
||||
// NOTE: RedirectSlashes middleware is *incompatible* with http.FileServer,
|
||||
// see https://github.com/go-chi/chi/issues/343
|
||||
func RedirectSlashes(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
var path string
|
||||
rctx := chi.RouteContext(r.Context())
|
||||
if rctx != nil && rctx.RoutePath != "" {
|
||||
path = rctx.RoutePath
|
||||
} else {
|
||||
path = r.URL.Path
|
||||
}
|
||||
if len(path) > 1 && path[len(path)-1] == '/' {
|
||||
if r.URL.RawQuery != "" {
|
||||
path = fmt.Sprintf("%s?%s", path[:len(path)-1], r.URL.RawQuery)
|
||||
} else {
|
||||
path = path[:len(path)-1]
|
||||
}
|
||||
redirectURL := fmt.Sprintf("//%s%s", r.Host, path)
|
||||
http.Redirect(w, r, redirectURL, 301)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
63
vendor/github.com/go-chi/chi/v5/middleware/terminal.go
generated
vendored
Normal file
63
vendor/github.com/go-chi/chi/v5/middleware/terminal.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package middleware
|
||||
|
||||
// Ported from Goji's middleware, source:
|
||||
// https://github.com/zenazn/goji/tree/master/web/middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
// Normal colors
|
||||
nBlack = []byte{'\033', '[', '3', '0', 'm'}
|
||||
nRed = []byte{'\033', '[', '3', '1', 'm'}
|
||||
nGreen = []byte{'\033', '[', '3', '2', 'm'}
|
||||
nYellow = []byte{'\033', '[', '3', '3', 'm'}
|
||||
nBlue = []byte{'\033', '[', '3', '4', 'm'}
|
||||
nMagenta = []byte{'\033', '[', '3', '5', 'm'}
|
||||
nCyan = []byte{'\033', '[', '3', '6', 'm'}
|
||||
nWhite = []byte{'\033', '[', '3', '7', 'm'}
|
||||
// Bright colors
|
||||
bBlack = []byte{'\033', '[', '3', '0', ';', '1', 'm'}
|
||||
bRed = []byte{'\033', '[', '3', '1', ';', '1', 'm'}
|
||||
bGreen = []byte{'\033', '[', '3', '2', ';', '1', 'm'}
|
||||
bYellow = []byte{'\033', '[', '3', '3', ';', '1', 'm'}
|
||||
bBlue = []byte{'\033', '[', '3', '4', ';', '1', 'm'}
|
||||
bMagenta = []byte{'\033', '[', '3', '5', ';', '1', 'm'}
|
||||
bCyan = []byte{'\033', '[', '3', '6', ';', '1', 'm'}
|
||||
bWhite = []byte{'\033', '[', '3', '7', ';', '1', 'm'}
|
||||
|
||||
reset = []byte{'\033', '[', '0', 'm'}
|
||||
)
|
||||
|
||||
var IsTTY bool
|
||||
|
||||
func init() {
|
||||
// This is sort of cheating: if stdout is a character device, we assume
|
||||
// that means it's a TTY. Unfortunately, there are many non-TTY
|
||||
// character devices, but fortunately stdout is rarely set to any of
|
||||
// them.
|
||||
//
|
||||
// We could solve this properly by pulling in a dependency on
|
||||
// code.google.com/p/go.crypto/ssh/terminal, for instance, but as a
|
||||
// heuristic for whether to print in color or in black-and-white, I'd
|
||||
// really rather not.
|
||||
fi, err := os.Stdout.Stat()
|
||||
if err == nil {
|
||||
m := os.ModeDevice | os.ModeCharDevice
|
||||
IsTTY = fi.Mode()&m == m
|
||||
}
|
||||
}
|
||||
|
||||
// colorWrite
|
||||
func cW(w io.Writer, useColor bool, color []byte, s string, args ...interface{}) {
|
||||
if IsTTY && useColor {
|
||||
w.Write(color)
|
||||
}
|
||||
fmt.Fprintf(w, s, args...)
|
||||
if IsTTY && useColor {
|
||||
w.Write(reset)
|
||||
}
|
||||
}
|
||||
132
vendor/github.com/go-chi/chi/v5/middleware/throttle.go
generated
vendored
Normal file
132
vendor/github.com/go-chi/chi/v5/middleware/throttle.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
errCapacityExceeded = "Server capacity exceeded."
|
||||
errTimedOut = "Timed out while waiting for a pending request to complete."
|
||||
errContextCanceled = "Context was canceled."
|
||||
)
|
||||
|
||||
var (
|
||||
defaultBacklogTimeout = time.Second * 60
|
||||
)
|
||||
|
||||
// ThrottleOpts represents a set of throttling options.
|
||||
type ThrottleOpts struct {
|
||||
Limit int
|
||||
BacklogLimit int
|
||||
BacklogTimeout time.Duration
|
||||
RetryAfterFn func(ctxDone bool) time.Duration
|
||||
}
|
||||
|
||||
// Throttle is a middleware that limits number of currently processed requests
|
||||
// at a time across all users. Note: Throttle is not a rate-limiter per user,
|
||||
// instead it just puts a ceiling on the number of currentl in-flight requests
|
||||
// being processed from the point from where the Throttle middleware is mounted.
|
||||
func Throttle(limit int) func(http.Handler) http.Handler {
|
||||
return ThrottleWithOpts(ThrottleOpts{Limit: limit, BacklogTimeout: defaultBacklogTimeout})
|
||||
}
|
||||
|
||||
// ThrottleBacklog is a middleware that limits number of currently processed
|
||||
// requests at a time and provides a backlog for holding a finite number of
|
||||
// pending requests.
|
||||
func ThrottleBacklog(limit, backlogLimit int, backlogTimeout time.Duration) func(http.Handler) http.Handler {
|
||||
return ThrottleWithOpts(ThrottleOpts{Limit: limit, BacklogLimit: backlogLimit, BacklogTimeout: backlogTimeout})
|
||||
}
|
||||
|
||||
// ThrottleWithOpts is a middleware that limits number of currently processed requests using passed ThrottleOpts.
|
||||
func ThrottleWithOpts(opts ThrottleOpts) func(http.Handler) http.Handler {
|
||||
if opts.Limit < 1 {
|
||||
panic("chi/middleware: Throttle expects limit > 0")
|
||||
}
|
||||
|
||||
if opts.BacklogLimit < 0 {
|
||||
panic("chi/middleware: Throttle expects backlogLimit to be positive")
|
||||
}
|
||||
|
||||
t := throttler{
|
||||
tokens: make(chan token, opts.Limit),
|
||||
backlogTokens: make(chan token, opts.Limit+opts.BacklogLimit),
|
||||
backlogTimeout: opts.BacklogTimeout,
|
||||
retryAfterFn: opts.RetryAfterFn,
|
||||
}
|
||||
|
||||
// Filling tokens.
|
||||
for i := 0; i < opts.Limit+opts.BacklogLimit; i++ {
|
||||
if i < opts.Limit {
|
||||
t.tokens <- token{}
|
||||
}
|
||||
t.backlogTokens <- token{}
|
||||
}
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
select {
|
||||
|
||||
case <-ctx.Done():
|
||||
t.setRetryAfterHeaderIfNeeded(w, true)
|
||||
http.Error(w, errContextCanceled, http.StatusTooManyRequests)
|
||||
return
|
||||
|
||||
case btok := <-t.backlogTokens:
|
||||
timer := time.NewTimer(t.backlogTimeout)
|
||||
|
||||
defer func() {
|
||||
t.backlogTokens <- btok
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-timer.C:
|
||||
t.setRetryAfterHeaderIfNeeded(w, false)
|
||||
http.Error(w, errTimedOut, http.StatusTooManyRequests)
|
||||
return
|
||||
case <-ctx.Done():
|
||||
timer.Stop()
|
||||
t.setRetryAfterHeaderIfNeeded(w, true)
|
||||
http.Error(w, errContextCanceled, http.StatusTooManyRequests)
|
||||
return
|
||||
case tok := <-t.tokens:
|
||||
defer func() {
|
||||
timer.Stop()
|
||||
t.tokens <- tok
|
||||
}()
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return
|
||||
|
||||
default:
|
||||
t.setRetryAfterHeaderIfNeeded(w, false)
|
||||
http.Error(w, errCapacityExceeded, http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
}
|
||||
|
||||
// token represents a request that is being processed.
|
||||
type token struct{}
|
||||
|
||||
// throttler limits number of currently processed requests at a time.
|
||||
type throttler struct {
|
||||
tokens chan token
|
||||
backlogTokens chan token
|
||||
backlogTimeout time.Duration
|
||||
retryAfterFn func(ctxDone bool) time.Duration
|
||||
}
|
||||
|
||||
// setRetryAfterHeaderIfNeeded sets Retry-After HTTP header if corresponding retryAfterFn option of throttler is initialized.
|
||||
func (t throttler) setRetryAfterHeaderIfNeeded(w http.ResponseWriter, ctxDone bool) {
|
||||
if t.retryAfterFn == nil {
|
||||
return
|
||||
}
|
||||
w.Header().Set("Retry-After", strconv.Itoa(int(t.retryAfterFn(ctxDone).Seconds())))
|
||||
}
|
||||
49
vendor/github.com/go-chi/chi/v5/middleware/timeout.go
generated
vendored
Normal file
49
vendor/github.com/go-chi/chi/v5/middleware/timeout.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Timeout is a middleware that cancels ctx after a given timeout and return
|
||||
// a 504 Gateway Timeout error to the client.
|
||||
//
|
||||
// It's required that you select the ctx.Done() channel to check for the signal
|
||||
// if the context has reached its deadline and return, otherwise the timeout
|
||||
// signal will be just ignored.
|
||||
//
|
||||
// ie. a route/handler may look like:
|
||||
//
|
||||
// r.Get("/long", func(w http.ResponseWriter, r *http.Request) {
|
||||
// ctx := r.Context()
|
||||
// processTime := time.Duration(rand.Intn(4)+1) * time.Second
|
||||
//
|
||||
// select {
|
||||
// case <-ctx.Done():
|
||||
// return
|
||||
//
|
||||
// case <-time.After(processTime):
|
||||
// // The above channel simulates some hard work.
|
||||
// }
|
||||
//
|
||||
// w.Write([]byte("done"))
|
||||
// })
|
||||
//
|
||||
func Timeout(timeout time.Duration) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), timeout)
|
||||
defer func() {
|
||||
cancel()
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
w.WriteHeader(http.StatusGatewayTimeout)
|
||||
}
|
||||
}()
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
}
|
||||
72
vendor/github.com/go-chi/chi/v5/middleware/url_format.go
generated
vendored
Normal file
72
vendor/github.com/go-chi/chi/v5/middleware/url_format.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
var (
|
||||
// URLFormatCtxKey is the context.Context key to store the URL format data
|
||||
// for a request.
|
||||
URLFormatCtxKey = &contextKey{"URLFormat"}
|
||||
)
|
||||
|
||||
// URLFormat is a middleware that parses the url extension from a request path and stores it
|
||||
// on the context as a string under the key `middleware.URLFormatCtxKey`. The middleware will
|
||||
// trim the suffix from the routing path and continue routing.
|
||||
//
|
||||
// Routers should not include a url parameter for the suffix when using this middleware.
|
||||
//
|
||||
// Sample usage.. for url paths: `/articles/1`, `/articles/1.json` and `/articles/1.xml`
|
||||
//
|
||||
// func routes() http.Handler {
|
||||
// r := chi.NewRouter()
|
||||
// r.Use(middleware.URLFormat)
|
||||
//
|
||||
// r.Get("/articles/{id}", ListArticles)
|
||||
//
|
||||
// return r
|
||||
// }
|
||||
//
|
||||
// func ListArticles(w http.ResponseWriter, r *http.Request) {
|
||||
// urlFormat, _ := r.Context().Value(middleware.URLFormatCtxKey).(string)
|
||||
//
|
||||
// switch urlFormat {
|
||||
// case "json":
|
||||
// render.JSON(w, r, articles)
|
||||
// case "xml:"
|
||||
// render.XML(w, r, articles)
|
||||
// default:
|
||||
// render.JSON(w, r, articles)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
func URLFormat(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var format string
|
||||
path := r.URL.Path
|
||||
|
||||
if strings.Index(path, ".") > 0 {
|
||||
base := strings.LastIndex(path, "/")
|
||||
idx := strings.LastIndex(path[base:], ".")
|
||||
|
||||
if idx > 0 {
|
||||
idx += base
|
||||
format = path[idx+1:]
|
||||
|
||||
rctx := chi.RouteContext(r.Context())
|
||||
rctx.RoutePath = path[:idx]
|
||||
}
|
||||
}
|
||||
|
||||
r = r.WithContext(context.WithValue(ctx, URLFormatCtxKey, format))
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
17
vendor/github.com/go-chi/chi/v5/middleware/value.go
generated
vendored
Normal file
17
vendor/github.com/go-chi/chi/v5/middleware/value.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// WithValue is a middleware that sets a given key/value in a context chain.
|
||||
func WithValue(key, val interface{}) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
r = r.WithContext(context.WithValue(r.Context(), key, val))
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
}
|
||||
165
vendor/github.com/go-chi/chi/v5/middleware/wrap_writer.go
generated
vendored
Normal file
165
vendor/github.com/go-chi/chi/v5/middleware/wrap_writer.go
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
package middleware
|
||||
|
||||
// The original work was derived from Goji's middleware, source:
|
||||
// https://github.com/zenazn/goji/tree/master/web/middleware
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// NewWrapResponseWriter wraps an http.ResponseWriter, returning a proxy that allows you to
|
||||
// hook into various parts of the response process.
|
||||
func NewWrapResponseWriter(w http.ResponseWriter, protoMajor int) WrapResponseWriter {
|
||||
_, fl := w.(http.Flusher)
|
||||
|
||||
bw := basicWriter{ResponseWriter: w}
|
||||
|
||||
if protoMajor == 2 {
|
||||
_, ps := w.(http.Pusher)
|
||||
if fl || ps {
|
||||
return &http2FancyWriter{bw}
|
||||
}
|
||||
} else {
|
||||
_, hj := w.(http.Hijacker)
|
||||
_, rf := w.(io.ReaderFrom)
|
||||
if fl || hj || rf {
|
||||
return &httpFancyWriter{bw}
|
||||
}
|
||||
}
|
||||
|
||||
return &bw
|
||||
}
|
||||
|
||||
// WrapResponseWriter is a proxy around an http.ResponseWriter that allows you to hook
|
||||
// into various parts of the response process.
|
||||
type WrapResponseWriter interface {
|
||||
http.ResponseWriter
|
||||
// Status returns the HTTP status of the request, or 0 if one has not
|
||||
// yet been sent.
|
||||
Status() int
|
||||
// BytesWritten returns the total number of bytes sent to the client.
|
||||
BytesWritten() int
|
||||
// Tee causes the response body to be written to the given io.Writer in
|
||||
// addition to proxying the writes through. Only one io.Writer can be
|
||||
// tee'd to at once: setting a second one will overwrite the first.
|
||||
// Writes will be sent to the proxy before being written to this
|
||||
// io.Writer. It is illegal for the tee'd writer to be modified
|
||||
// concurrently with writes.
|
||||
Tee(io.Writer)
|
||||
// Unwrap returns the original proxied target.
|
||||
Unwrap() http.ResponseWriter
|
||||
}
|
||||
|
||||
// basicWriter wraps a http.ResponseWriter that implements the minimal
|
||||
// http.ResponseWriter interface.
|
||||
type basicWriter struct {
|
||||
http.ResponseWriter
|
||||
wroteHeader bool
|
||||
code int
|
||||
bytes int
|
||||
tee io.Writer
|
||||
}
|
||||
|
||||
func (b *basicWriter) WriteHeader(code int) {
|
||||
if !b.wroteHeader {
|
||||
b.code = code
|
||||
b.wroteHeader = true
|
||||
b.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *basicWriter) Write(buf []byte) (int, error) {
|
||||
b.maybeWriteHeader()
|
||||
n, err := b.ResponseWriter.Write(buf)
|
||||
if b.tee != nil {
|
||||
_, err2 := b.tee.Write(buf[:n])
|
||||
// Prefer errors generated by the proxied writer.
|
||||
if err == nil {
|
||||
err = err2
|
||||
}
|
||||
}
|
||||
b.bytes += n
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (b *basicWriter) maybeWriteHeader() {
|
||||
if !b.wroteHeader {
|
||||
b.WriteHeader(http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *basicWriter) Status() int {
|
||||
return b.code
|
||||
}
|
||||
|
||||
func (b *basicWriter) BytesWritten() int {
|
||||
return b.bytes
|
||||
}
|
||||
|
||||
func (b *basicWriter) Tee(w io.Writer) {
|
||||
b.tee = w
|
||||
}
|
||||
|
||||
func (b *basicWriter) Unwrap() http.ResponseWriter {
|
||||
return b.ResponseWriter
|
||||
}
|
||||
|
||||
// httpFancyWriter is a HTTP writer that additionally satisfies
|
||||
// http.Flusher, http.Hijacker, and io.ReaderFrom. It exists for the common case
|
||||
// of wrapping the http.ResponseWriter that package http gives you, in order to
|
||||
// make the proxied object support the full method set of the proxied object.
|
||||
type httpFancyWriter struct {
|
||||
basicWriter
|
||||
}
|
||||
|
||||
func (f *httpFancyWriter) Flush() {
|
||||
f.wroteHeader = true
|
||||
fl := f.basicWriter.ResponseWriter.(http.Flusher)
|
||||
fl.Flush()
|
||||
}
|
||||
|
||||
func (f *httpFancyWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
hj := f.basicWriter.ResponseWriter.(http.Hijacker)
|
||||
return hj.Hijack()
|
||||
}
|
||||
|
||||
func (f *httpFancyWriter) ReadFrom(r io.Reader) (int64, error) {
|
||||
if f.basicWriter.tee != nil {
|
||||
n, err := io.Copy(&f.basicWriter, r)
|
||||
f.basicWriter.bytes += int(n)
|
||||
return n, err
|
||||
}
|
||||
rf := f.basicWriter.ResponseWriter.(io.ReaderFrom)
|
||||
f.basicWriter.maybeWriteHeader()
|
||||
n, err := rf.ReadFrom(r)
|
||||
f.basicWriter.bytes += int(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
var _ http.Flusher = &httpFancyWriter{}
|
||||
var _ http.Hijacker = &httpFancyWriter{}
|
||||
var _ io.ReaderFrom = &httpFancyWriter{}
|
||||
|
||||
// http2FancyWriter is a HTTP2 writer that additionally satisfies
|
||||
// http.Flusher, and io.ReaderFrom. It exists for the common case
|
||||
// of wrapping the http.ResponseWriter that package http gives you, in order to
|
||||
// make the proxied object support the full method set of the proxied object.
|
||||
type http2FancyWriter struct {
|
||||
basicWriter
|
||||
}
|
||||
|
||||
func (f *http2FancyWriter) Flush() {
|
||||
f.wroteHeader = true
|
||||
fl := f.basicWriter.ResponseWriter.(http.Flusher)
|
||||
fl.Flush()
|
||||
}
|
||||
|
||||
func (f *http2FancyWriter) Push(target string, opts *http.PushOptions) error {
|
||||
return f.basicWriter.ResponseWriter.(http.Pusher).Push(target, opts)
|
||||
}
|
||||
|
||||
var _ http.Flusher = &http2FancyWriter{}
|
||||
var _ http.Pusher = &http2FancyWriter{}
|
||||
479
vendor/github.com/go-chi/chi/v5/mux.go
generated
vendored
Normal file
479
vendor/github.com/go-chi/chi/v5/mux.go
generated
vendored
Normal file
@@ -0,0 +1,479 @@
|
||||
package chi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var _ Router = &Mux{}
|
||||
|
||||
// Mux is a simple HTTP route multiplexer that parses a request path,
|
||||
// records any URL params, and executes an end handler. It implements
|
||||
// the http.Handler interface and is friendly with the standard library.
|
||||
//
|
||||
// Mux is designed to be fast, minimal and offer a powerful API for building
|
||||
// modular and composable HTTP services with a large set of handlers. It's
|
||||
// particularly useful for writing large REST API services that break a handler
|
||||
// into many smaller parts composed of middlewares and end handlers.
|
||||
type Mux struct {
|
||||
// The radix trie router
|
||||
tree *node
|
||||
|
||||
// The middleware stack
|
||||
middlewares []func(http.Handler) http.Handler
|
||||
|
||||
// Controls the behaviour of middleware chain generation when a mux
|
||||
// is registered as an inline group inside another mux.
|
||||
inline bool
|
||||
parent *Mux
|
||||
|
||||
// The computed mux handler made of the chained middleware stack and
|
||||
// the tree router
|
||||
handler http.Handler
|
||||
|
||||
// Routing context pool
|
||||
pool *sync.Pool
|
||||
|
||||
// Custom route not found handler
|
||||
notFoundHandler http.HandlerFunc
|
||||
|
||||
// Custom method not allowed handler
|
||||
methodNotAllowedHandler http.HandlerFunc
|
||||
}
|
||||
|
||||
// NewMux returns a newly initialized Mux object that implements the Router
|
||||
// interface.
|
||||
func NewMux() *Mux {
|
||||
mux := &Mux{tree: &node{}, pool: &sync.Pool{}}
|
||||
mux.pool.New = func() interface{} {
|
||||
return NewRouteContext()
|
||||
}
|
||||
return mux
|
||||
}
|
||||
|
||||
// ServeHTTP is the single method of the http.Handler interface that makes
|
||||
// Mux interoperable with the standard library. It uses a sync.Pool to get and
|
||||
// reuse routing contexts for each request.
|
||||
func (mx *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Ensure the mux has some routes defined on the mux
|
||||
if mx.handler == nil {
|
||||
mx.NotFoundHandler().ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if a routing context already exists from a parent router.
|
||||
rctx, _ := r.Context().Value(RouteCtxKey).(*Context)
|
||||
if rctx != nil {
|
||||
mx.handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch a RouteContext object from the sync pool, and call the computed
|
||||
// mx.handler that is comprised of mx.middlewares + mx.routeHTTP.
|
||||
// Once the request is finished, reset the routing context and put it back
|
||||
// into the pool for reuse from another request.
|
||||
rctx = mx.pool.Get().(*Context)
|
||||
rctx.Reset()
|
||||
rctx.Routes = mx
|
||||
rctx.parentCtx = r.Context()
|
||||
|
||||
// NOTE: r.WithContext() causes 2 allocations and context.WithValue() causes 1 allocation
|
||||
r = r.WithContext(context.WithValue(r.Context(), RouteCtxKey, rctx))
|
||||
|
||||
// Serve the request and once its done, put the request context back in the sync pool
|
||||
mx.handler.ServeHTTP(w, r)
|
||||
mx.pool.Put(rctx)
|
||||
}
|
||||
|
||||
// Use appends a middleware handler to the Mux middleware stack.
|
||||
//
|
||||
// The middleware stack for any Mux will execute before searching for a matching
|
||||
// route to a specific handler, which provides opportunity to respond early,
|
||||
// change the course of the request execution, or set request-scoped values for
|
||||
// the next http.Handler.
|
||||
func (mx *Mux) Use(middlewares ...func(http.Handler) http.Handler) {
|
||||
if mx.handler != nil {
|
||||
panic("chi: all middlewares must be defined before routes on a mux")
|
||||
}
|
||||
mx.middlewares = append(mx.middlewares, middlewares...)
|
||||
}
|
||||
|
||||
// Handle adds the route `pattern` that matches any http method to
|
||||
// execute the `handler` http.Handler.
|
||||
func (mx *Mux) Handle(pattern string, handler http.Handler) {
|
||||
mx.handle(mALL, pattern, handler)
|
||||
}
|
||||
|
||||
// HandleFunc adds the route `pattern` that matches any http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) HandleFunc(pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.handle(mALL, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Method adds the route `pattern` that matches `method` http method to
|
||||
// execute the `handler` http.Handler.
|
||||
func (mx *Mux) Method(method, pattern string, handler http.Handler) {
|
||||
m, ok := methodMap[strings.ToUpper(method)]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("chi: '%s' http method is not supported.", method))
|
||||
}
|
||||
mx.handle(m, pattern, handler)
|
||||
}
|
||||
|
||||
// MethodFunc adds the route `pattern` that matches `method` http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) MethodFunc(method, pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.Method(method, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Connect adds the route `pattern` that matches a CONNECT http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) Connect(pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.handle(mCONNECT, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Delete adds the route `pattern` that matches a DELETE http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) Delete(pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.handle(mDELETE, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Get adds the route `pattern` that matches a GET http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) Get(pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.handle(mGET, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Head adds the route `pattern` that matches a HEAD http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) Head(pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.handle(mHEAD, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Options adds the route `pattern` that matches a OPTIONS http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) Options(pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.handle(mOPTIONS, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Patch adds the route `pattern` that matches a PATCH http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) Patch(pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.handle(mPATCH, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Post adds the route `pattern` that matches a POST http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) Post(pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.handle(mPOST, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Put adds the route `pattern` that matches a PUT http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) Put(pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.handle(mPUT, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// Trace adds the route `pattern` that matches a TRACE http method to
|
||||
// execute the `handlerFn` http.HandlerFunc.
|
||||
func (mx *Mux) Trace(pattern string, handlerFn http.HandlerFunc) {
|
||||
mx.handle(mTRACE, pattern, handlerFn)
|
||||
}
|
||||
|
||||
// NotFound sets a custom http.HandlerFunc for routing paths that could
|
||||
// not be found. The default 404 handler is `http.NotFound`.
|
||||
func (mx *Mux) NotFound(handlerFn http.HandlerFunc) {
|
||||
// Build NotFound handler chain
|
||||
m := mx
|
||||
h := Chain(mx.middlewares...).HandlerFunc(handlerFn).ServeHTTP
|
||||
if mx.inline && mx.parent != nil {
|
||||
m = mx.parent
|
||||
}
|
||||
|
||||
// Update the notFoundHandler from this point forward
|
||||
m.notFoundHandler = h
|
||||
m.updateSubRoutes(func(subMux *Mux) {
|
||||
if subMux.notFoundHandler == nil {
|
||||
subMux.NotFound(h)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// MethodNotAllowed sets a custom http.HandlerFunc for routing paths where the
|
||||
// method is unresolved. The default handler returns a 405 with an empty body.
|
||||
func (mx *Mux) MethodNotAllowed(handlerFn http.HandlerFunc) {
|
||||
// Build MethodNotAllowed handler chain
|
||||
m := mx
|
||||
h := Chain(mx.middlewares...).HandlerFunc(handlerFn).ServeHTTP
|
||||
if mx.inline && mx.parent != nil {
|
||||
m = mx.parent
|
||||
}
|
||||
|
||||
// Update the methodNotAllowedHandler from this point forward
|
||||
m.methodNotAllowedHandler = h
|
||||
m.updateSubRoutes(func(subMux *Mux) {
|
||||
if subMux.methodNotAllowedHandler == nil {
|
||||
subMux.MethodNotAllowed(h)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// With adds inline middlewares for an endpoint handler.
|
||||
func (mx *Mux) With(middlewares ...func(http.Handler) http.Handler) Router {
|
||||
// Similarly as in handle(), we must build the mux handler once additional
|
||||
// middleware registration isn't allowed for this stack, like now.
|
||||
if !mx.inline && mx.handler == nil {
|
||||
mx.updateRouteHandler()
|
||||
}
|
||||
|
||||
// Copy middlewares from parent inline muxs
|
||||
var mws Middlewares
|
||||
if mx.inline {
|
||||
mws = make(Middlewares, len(mx.middlewares))
|
||||
copy(mws, mx.middlewares)
|
||||
}
|
||||
mws = append(mws, middlewares...)
|
||||
|
||||
im := &Mux{
|
||||
pool: mx.pool, inline: true, parent: mx, tree: mx.tree, middlewares: mws,
|
||||
notFoundHandler: mx.notFoundHandler, methodNotAllowedHandler: mx.methodNotAllowedHandler,
|
||||
}
|
||||
|
||||
return im
|
||||
}
|
||||
|
||||
// Group creates a new inline-Mux with a fresh middleware stack. It's useful
|
||||
// for a group of handlers along the same routing path that use an additional
|
||||
// set of middlewares. See _examples/.
|
||||
func (mx *Mux) Group(fn func(r Router)) Router {
|
||||
im := mx.With().(*Mux)
|
||||
if fn != nil {
|
||||
fn(im)
|
||||
}
|
||||
return im
|
||||
}
|
||||
|
||||
// Route creates a new Mux with a fresh middleware stack and mounts it
|
||||
// along the `pattern` as a subrouter. Effectively, this is a short-hand
|
||||
// call to Mount. See _examples/.
|
||||
func (mx *Mux) Route(pattern string, fn func(r Router)) Router {
|
||||
if fn == nil {
|
||||
panic(fmt.Sprintf("chi: attempting to Route() a nil subrouter on '%s'", pattern))
|
||||
}
|
||||
subRouter := NewRouter()
|
||||
fn(subRouter)
|
||||
mx.Mount(pattern, subRouter)
|
||||
return subRouter
|
||||
}
|
||||
|
||||
// Mount attaches another http.Handler or chi Router as a subrouter along a routing
|
||||
// path. It's very useful to split up a large API as many independent routers and
|
||||
// compose them as a single service using Mount. See _examples/.
|
||||
//
|
||||
// Note that Mount() simply sets a wildcard along the `pattern` that will continue
|
||||
// routing at the `handler`, which in most cases is another chi.Router. As a result,
|
||||
// if you define two Mount() routes on the exact same pattern the mount will panic.
|
||||
func (mx *Mux) Mount(pattern string, handler http.Handler) {
|
||||
if handler == nil {
|
||||
panic(fmt.Sprintf("chi: attempting to Mount() a nil handler on '%s'", pattern))
|
||||
}
|
||||
|
||||
// Provide runtime safety for ensuring a pattern isn't mounted on an existing
|
||||
// routing pattern.
|
||||
if mx.tree.findPattern(pattern+"*") || mx.tree.findPattern(pattern+"/*") {
|
||||
panic(fmt.Sprintf("chi: attempting to Mount() a handler on an existing path, '%s'", pattern))
|
||||
}
|
||||
|
||||
// Assign sub-Router's with the parent not found & method not allowed handler if not specified.
|
||||
subr, ok := handler.(*Mux)
|
||||
if ok && subr.notFoundHandler == nil && mx.notFoundHandler != nil {
|
||||
subr.NotFound(mx.notFoundHandler)
|
||||
}
|
||||
if ok && subr.methodNotAllowedHandler == nil && mx.methodNotAllowedHandler != nil {
|
||||
subr.MethodNotAllowed(mx.methodNotAllowedHandler)
|
||||
}
|
||||
|
||||
mountHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
rctx := RouteContext(r.Context())
|
||||
|
||||
// shift the url path past the previous subrouter
|
||||
rctx.RoutePath = mx.nextRoutePath(rctx)
|
||||
|
||||
// reset the wildcard URLParam which connects the subrouter
|
||||
n := len(rctx.URLParams.Keys) - 1
|
||||
if n >= 0 && rctx.URLParams.Keys[n] == "*" && len(rctx.URLParams.Values) > n {
|
||||
rctx.URLParams.Values[n] = ""
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
})
|
||||
|
||||
if pattern == "" || pattern[len(pattern)-1] != '/' {
|
||||
mx.handle(mALL|mSTUB, pattern, mountHandler)
|
||||
mx.handle(mALL|mSTUB, pattern+"/", mountHandler)
|
||||
pattern += "/"
|
||||
}
|
||||
|
||||
method := mALL
|
||||
subroutes, _ := handler.(Routes)
|
||||
if subroutes != nil {
|
||||
method |= mSTUB
|
||||
}
|
||||
n := mx.handle(method, pattern+"*", mountHandler)
|
||||
|
||||
if subroutes != nil {
|
||||
n.subroutes = subroutes
|
||||
}
|
||||
}
|
||||
|
||||
// Routes returns a slice of routing information from the tree,
|
||||
// useful for traversing available routes of a router.
|
||||
func (mx *Mux) Routes() []Route {
|
||||
return mx.tree.routes()
|
||||
}
|
||||
|
||||
// Middlewares returns a slice of middleware handler functions.
|
||||
func (mx *Mux) Middlewares() Middlewares {
|
||||
return mx.middlewares
|
||||
}
|
||||
|
||||
// Match searches the routing tree for a handler that matches the method/path.
|
||||
// It's similar to routing a http request, but without executing the handler
|
||||
// thereafter.
|
||||
//
|
||||
// Note: the *Context state is updated during execution, so manage
|
||||
// the state carefully or make a NewRouteContext().
|
||||
func (mx *Mux) Match(rctx *Context, method, path string) bool {
|
||||
m, ok := methodMap[method]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
node, _, h := mx.tree.FindRoute(rctx, m, path)
|
||||
|
||||
if node != nil && node.subroutes != nil {
|
||||
rctx.RoutePath = mx.nextRoutePath(rctx)
|
||||
return node.subroutes.Match(rctx, method, rctx.RoutePath)
|
||||
}
|
||||
|
||||
return h != nil
|
||||
}
|
||||
|
||||
// NotFoundHandler returns the default Mux 404 responder whenever a route
|
||||
// cannot be found.
|
||||
func (mx *Mux) NotFoundHandler() http.HandlerFunc {
|
||||
if mx.notFoundHandler != nil {
|
||||
return mx.notFoundHandler
|
||||
}
|
||||
return http.NotFound
|
||||
}
|
||||
|
||||
// MethodNotAllowedHandler returns the default Mux 405 responder whenever
|
||||
// a method cannot be resolved for a route.
|
||||
func (mx *Mux) MethodNotAllowedHandler() http.HandlerFunc {
|
||||
if mx.methodNotAllowedHandler != nil {
|
||||
return mx.methodNotAllowedHandler
|
||||
}
|
||||
return methodNotAllowedHandler
|
||||
}
|
||||
|
||||
// handle registers a http.Handler in the routing tree for a particular http method
|
||||
// and routing pattern.
|
||||
func (mx *Mux) handle(method methodTyp, pattern string, handler http.Handler) *node {
|
||||
if len(pattern) == 0 || pattern[0] != '/' {
|
||||
panic(fmt.Sprintf("chi: routing pattern must begin with '/' in '%s'", pattern))
|
||||
}
|
||||
|
||||
// Build the computed routing handler for this routing pattern.
|
||||
if !mx.inline && mx.handler == nil {
|
||||
mx.updateRouteHandler()
|
||||
}
|
||||
|
||||
// Build endpoint handler with inline middlewares for the route
|
||||
var h http.Handler
|
||||
if mx.inline {
|
||||
mx.handler = http.HandlerFunc(mx.routeHTTP)
|
||||
h = Chain(mx.middlewares...).Handler(handler)
|
||||
} else {
|
||||
h = handler
|
||||
}
|
||||
|
||||
// Add the endpoint to the tree and return the node
|
||||
return mx.tree.InsertRoute(method, pattern, h)
|
||||
}
|
||||
|
||||
// routeHTTP routes a http.Request through the Mux routing tree to serve
|
||||
// the matching handler for a particular http method.
|
||||
func (mx *Mux) routeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Grab the route context object
|
||||
rctx := r.Context().Value(RouteCtxKey).(*Context)
|
||||
|
||||
// The request routing path
|
||||
routePath := rctx.RoutePath
|
||||
if routePath == "" {
|
||||
if r.URL.RawPath != "" {
|
||||
routePath = r.URL.RawPath
|
||||
} else {
|
||||
routePath = r.URL.Path
|
||||
}
|
||||
}
|
||||
|
||||
// Check if method is supported by chi
|
||||
if rctx.RouteMethod == "" {
|
||||
rctx.RouteMethod = r.Method
|
||||
}
|
||||
method, ok := methodMap[rctx.RouteMethod]
|
||||
if !ok {
|
||||
mx.MethodNotAllowedHandler().ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// Find the route
|
||||
if _, _, h := mx.tree.FindRoute(rctx, method, routePath); h != nil {
|
||||
h.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
if rctx.methodNotAllowed {
|
||||
mx.MethodNotAllowedHandler().ServeHTTP(w, r)
|
||||
} else {
|
||||
mx.NotFoundHandler().ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (mx *Mux) nextRoutePath(rctx *Context) string {
|
||||
routePath := "/"
|
||||
nx := len(rctx.routeParams.Keys) - 1 // index of last param in list
|
||||
if nx >= 0 && rctx.routeParams.Keys[nx] == "*" && len(rctx.routeParams.Values) > nx {
|
||||
routePath = "/" + rctx.routeParams.Values[nx]
|
||||
}
|
||||
return routePath
|
||||
}
|
||||
|
||||
// Recursively update data on child routers.
|
||||
func (mx *Mux) updateSubRoutes(fn func(subMux *Mux)) {
|
||||
for _, r := range mx.tree.routes() {
|
||||
subMux, ok := r.SubRoutes.(*Mux)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
fn(subMux)
|
||||
}
|
||||
}
|
||||
|
||||
// updateRouteHandler builds the single mux handler that is a chain of the middleware
|
||||
// stack, as defined by calls to Use(), and the tree router (Mux) itself. After this
|
||||
// point, no other middlewares can be registered on this Mux's stack. But you can still
|
||||
// compose additional middlewares via Group()'s or using a chained middleware handler.
|
||||
func (mx *Mux) updateRouteHandler() {
|
||||
mx.handler = chain(mx.middlewares, http.HandlerFunc(mx.routeHTTP))
|
||||
}
|
||||
|
||||
// methodNotAllowedHandler is a helper function to respond with a 405,
|
||||
// method not allowed.
|
||||
func methodNotAllowedHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(405)
|
||||
w.Write(nil)
|
||||
}
|
||||
866
vendor/github.com/go-chi/chi/v5/tree.go
generated
vendored
Normal file
866
vendor/github.com/go-chi/chi/v5/tree.go
generated
vendored
Normal file
@@ -0,0 +1,866 @@
|
||||
package chi
|
||||
|
||||
// Radix tree implementation below is a based on the original work by
|
||||
// Armon Dadgar in https://github.com/armon/go-radix/blob/master/radix.go
|
||||
// (MIT licensed). It's been heavily modified for use as a HTTP routing tree.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type methodTyp int
|
||||
|
||||
const (
|
||||
mSTUB methodTyp = 1 << iota
|
||||
mCONNECT
|
||||
mDELETE
|
||||
mGET
|
||||
mHEAD
|
||||
mOPTIONS
|
||||
mPATCH
|
||||
mPOST
|
||||
mPUT
|
||||
mTRACE
|
||||
)
|
||||
|
||||
var mALL = mCONNECT | mDELETE | mGET | mHEAD |
|
||||
mOPTIONS | mPATCH | mPOST | mPUT | mTRACE
|
||||
|
||||
var methodMap = map[string]methodTyp{
|
||||
http.MethodConnect: mCONNECT,
|
||||
http.MethodDelete: mDELETE,
|
||||
http.MethodGet: mGET,
|
||||
http.MethodHead: mHEAD,
|
||||
http.MethodOptions: mOPTIONS,
|
||||
http.MethodPatch: mPATCH,
|
||||
http.MethodPost: mPOST,
|
||||
http.MethodPut: mPUT,
|
||||
http.MethodTrace: mTRACE,
|
||||
}
|
||||
|
||||
// RegisterMethod adds support for custom HTTP method handlers, available
|
||||
// via Router#Method and Router#MethodFunc
|
||||
func RegisterMethod(method string) {
|
||||
if method == "" {
|
||||
return
|
||||
}
|
||||
method = strings.ToUpper(method)
|
||||
if _, ok := methodMap[method]; ok {
|
||||
return
|
||||
}
|
||||
n := len(methodMap)
|
||||
if n > strconv.IntSize-2 {
|
||||
panic(fmt.Sprintf("chi: max number of methods reached (%d)", strconv.IntSize))
|
||||
}
|
||||
mt := methodTyp(2 << n)
|
||||
methodMap[method] = mt
|
||||
mALL |= mt
|
||||
}
|
||||
|
||||
type nodeTyp uint8
|
||||
|
||||
const (
|
||||
ntStatic nodeTyp = iota // /home
|
||||
ntRegexp // /{id:[0-9]+}
|
||||
ntParam // /{user}
|
||||
ntCatchAll // /api/v1/*
|
||||
)
|
||||
|
||||
type node struct {
|
||||
// node type: static, regexp, param, catchAll
|
||||
typ nodeTyp
|
||||
|
||||
// first byte of the prefix
|
||||
label byte
|
||||
|
||||
// first byte of the child prefix
|
||||
tail byte
|
||||
|
||||
// prefix is the common prefix we ignore
|
||||
prefix string
|
||||
|
||||
// regexp matcher for regexp nodes
|
||||
rex *regexp.Regexp
|
||||
|
||||
// HTTP handler endpoints on the leaf node
|
||||
endpoints endpoints
|
||||
|
||||
// subroutes on the leaf node
|
||||
subroutes Routes
|
||||
|
||||
// child nodes should be stored in-order for iteration,
|
||||
// in groups of the node type.
|
||||
children [ntCatchAll + 1]nodes
|
||||
}
|
||||
|
||||
// endpoints is a mapping of http method constants to handlers
|
||||
// for a given route.
|
||||
type endpoints map[methodTyp]*endpoint
|
||||
|
||||
type endpoint struct {
|
||||
// endpoint handler
|
||||
handler http.Handler
|
||||
|
||||
// pattern is the routing pattern for handler nodes
|
||||
pattern string
|
||||
|
||||
// parameter keys recorded on handler nodes
|
||||
paramKeys []string
|
||||
}
|
||||
|
||||
func (s endpoints) Value(method methodTyp) *endpoint {
|
||||
mh, ok := s[method]
|
||||
if !ok {
|
||||
mh = &endpoint{}
|
||||
s[method] = mh
|
||||
}
|
||||
return mh
|
||||
}
|
||||
|
||||
func (n *node) InsertRoute(method methodTyp, pattern string, handler http.Handler) *node {
|
||||
var parent *node
|
||||
search := pattern
|
||||
|
||||
for {
|
||||
// Handle key exhaustion
|
||||
if len(search) == 0 {
|
||||
// Insert or update the node's leaf handler
|
||||
n.setEndpoint(method, handler, pattern)
|
||||
return n
|
||||
}
|
||||
|
||||
// We're going to be searching for a wild node next,
|
||||
// in this case, we need to get the tail
|
||||
var label = search[0]
|
||||
var segTail byte
|
||||
var segEndIdx int
|
||||
var segTyp nodeTyp
|
||||
var segRexpat string
|
||||
if label == '{' || label == '*' {
|
||||
segTyp, _, segRexpat, segTail, _, segEndIdx = patNextSegment(search)
|
||||
}
|
||||
|
||||
var prefix string
|
||||
if segTyp == ntRegexp {
|
||||
prefix = segRexpat
|
||||
}
|
||||
|
||||
// Look for the edge to attach to
|
||||
parent = n
|
||||
n = n.getEdge(segTyp, label, segTail, prefix)
|
||||
|
||||
// No edge, create one
|
||||
if n == nil {
|
||||
child := &node{label: label, tail: segTail, prefix: search}
|
||||
hn := parent.addChild(child, search)
|
||||
hn.setEndpoint(method, handler, pattern)
|
||||
|
||||
return hn
|
||||
}
|
||||
|
||||
// Found an edge to match the pattern
|
||||
|
||||
if n.typ > ntStatic {
|
||||
// We found a param node, trim the param from the search path and continue.
|
||||
// This param/wild pattern segment would already be on the tree from a previous
|
||||
// call to addChild when creating a new node.
|
||||
search = search[segEndIdx:]
|
||||
continue
|
||||
}
|
||||
|
||||
// Static nodes fall below here.
|
||||
// Determine longest prefix of the search key on match.
|
||||
commonPrefix := longestPrefix(search, n.prefix)
|
||||
if commonPrefix == len(n.prefix) {
|
||||
// the common prefix is as long as the current node's prefix we're attempting to insert.
|
||||
// keep the search going.
|
||||
search = search[commonPrefix:]
|
||||
continue
|
||||
}
|
||||
|
||||
// Split the node
|
||||
child := &node{
|
||||
typ: ntStatic,
|
||||
prefix: search[:commonPrefix],
|
||||
}
|
||||
parent.replaceChild(search[0], segTail, child)
|
||||
|
||||
// Restore the existing node
|
||||
n.label = n.prefix[commonPrefix]
|
||||
n.prefix = n.prefix[commonPrefix:]
|
||||
child.addChild(n, n.prefix)
|
||||
|
||||
// If the new key is a subset, set the method/handler on this node and finish.
|
||||
search = search[commonPrefix:]
|
||||
if len(search) == 0 {
|
||||
child.setEndpoint(method, handler, pattern)
|
||||
return child
|
||||
}
|
||||
|
||||
// Create a new edge for the node
|
||||
subchild := &node{
|
||||
typ: ntStatic,
|
||||
label: search[0],
|
||||
prefix: search,
|
||||
}
|
||||
hn := child.addChild(subchild, search)
|
||||
hn.setEndpoint(method, handler, pattern)
|
||||
return hn
|
||||
}
|
||||
}
|
||||
|
||||
// addChild appends the new `child` node to the tree using the `pattern` as the trie key.
|
||||
// For a URL router like chi's, we split the static, param, regexp and wildcard segments
|
||||
// into different nodes. In addition, addChild will recursively call itself until every
|
||||
// pattern segment is added to the url pattern tree as individual nodes, depending on type.
|
||||
func (n *node) addChild(child *node, prefix string) *node {
|
||||
search := prefix
|
||||
|
||||
// handler leaf node added to the tree is the child.
|
||||
// this may be overridden later down the flow
|
||||
hn := child
|
||||
|
||||
// Parse next segment
|
||||
segTyp, _, segRexpat, segTail, segStartIdx, segEndIdx := patNextSegment(search)
|
||||
|
||||
// Add child depending on next up segment
|
||||
switch segTyp {
|
||||
|
||||
case ntStatic:
|
||||
// Search prefix is all static (that is, has no params in path)
|
||||
// noop
|
||||
|
||||
default:
|
||||
// Search prefix contains a param, regexp or wildcard
|
||||
|
||||
if segTyp == ntRegexp {
|
||||
rex, err := regexp.Compile(segRexpat)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("chi: invalid regexp pattern '%s' in route param", segRexpat))
|
||||
}
|
||||
child.prefix = segRexpat
|
||||
child.rex = rex
|
||||
}
|
||||
|
||||
if segStartIdx == 0 {
|
||||
// Route starts with a param
|
||||
child.typ = segTyp
|
||||
|
||||
if segTyp == ntCatchAll {
|
||||
segStartIdx = -1
|
||||
} else {
|
||||
segStartIdx = segEndIdx
|
||||
}
|
||||
if segStartIdx < 0 {
|
||||
segStartIdx = len(search)
|
||||
}
|
||||
child.tail = segTail // for params, we set the tail
|
||||
|
||||
if segStartIdx != len(search) {
|
||||
// add static edge for the remaining part, split the end.
|
||||
// its not possible to have adjacent param nodes, so its certainly
|
||||
// going to be a static node next.
|
||||
|
||||
search = search[segStartIdx:] // advance search position
|
||||
|
||||
nn := &node{
|
||||
typ: ntStatic,
|
||||
label: search[0],
|
||||
prefix: search,
|
||||
}
|
||||
hn = child.addChild(nn, search)
|
||||
}
|
||||
|
||||
} else if segStartIdx > 0 {
|
||||
// Route has some param
|
||||
|
||||
// starts with a static segment
|
||||
child.typ = ntStatic
|
||||
child.prefix = search[:segStartIdx]
|
||||
child.rex = nil
|
||||
|
||||
// add the param edge node
|
||||
search = search[segStartIdx:]
|
||||
|
||||
nn := &node{
|
||||
typ: segTyp,
|
||||
label: search[0],
|
||||
tail: segTail,
|
||||
}
|
||||
hn = child.addChild(nn, search)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
n.children[child.typ] = append(n.children[child.typ], child)
|
||||
n.children[child.typ].Sort()
|
||||
return hn
|
||||
}
|
||||
|
||||
func (n *node) replaceChild(label, tail byte, child *node) {
|
||||
for i := 0; i < len(n.children[child.typ]); i++ {
|
||||
if n.children[child.typ][i].label == label && n.children[child.typ][i].tail == tail {
|
||||
n.children[child.typ][i] = child
|
||||
n.children[child.typ][i].label = label
|
||||
n.children[child.typ][i].tail = tail
|
||||
return
|
||||
}
|
||||
}
|
||||
panic("chi: replacing missing child")
|
||||
}
|
||||
|
||||
func (n *node) getEdge(ntyp nodeTyp, label, tail byte, prefix string) *node {
|
||||
nds := n.children[ntyp]
|
||||
for i := 0; i < len(nds); i++ {
|
||||
if nds[i].label == label && nds[i].tail == tail {
|
||||
if ntyp == ntRegexp && nds[i].prefix != prefix {
|
||||
continue
|
||||
}
|
||||
return nds[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *node) setEndpoint(method methodTyp, handler http.Handler, pattern string) {
|
||||
// Set the handler for the method type on the node
|
||||
if n.endpoints == nil {
|
||||
n.endpoints = make(endpoints)
|
||||
}
|
||||
|
||||
paramKeys := patParamKeys(pattern)
|
||||
|
||||
if method&mSTUB == mSTUB {
|
||||
n.endpoints.Value(mSTUB).handler = handler
|
||||
}
|
||||
if method&mALL == mALL {
|
||||
h := n.endpoints.Value(mALL)
|
||||
h.handler = handler
|
||||
h.pattern = pattern
|
||||
h.paramKeys = paramKeys
|
||||
for _, m := range methodMap {
|
||||
h := n.endpoints.Value(m)
|
||||
h.handler = handler
|
||||
h.pattern = pattern
|
||||
h.paramKeys = paramKeys
|
||||
}
|
||||
} else {
|
||||
h := n.endpoints.Value(method)
|
||||
h.handler = handler
|
||||
h.pattern = pattern
|
||||
h.paramKeys = paramKeys
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) FindRoute(rctx *Context, method methodTyp, path string) (*node, endpoints, http.Handler) {
|
||||
// Reset the context routing pattern and params
|
||||
rctx.routePattern = ""
|
||||
rctx.routeParams.Keys = rctx.routeParams.Keys[:0]
|
||||
rctx.routeParams.Values = rctx.routeParams.Values[:0]
|
||||
|
||||
// Find the routing handlers for the path
|
||||
rn := n.findRoute(rctx, method, path)
|
||||
if rn == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
// Record the routing params in the request lifecycle
|
||||
rctx.URLParams.Keys = append(rctx.URLParams.Keys, rctx.routeParams.Keys...)
|
||||
rctx.URLParams.Values = append(rctx.URLParams.Values, rctx.routeParams.Values...)
|
||||
|
||||
// Record the routing pattern in the request lifecycle
|
||||
if rn.endpoints[method].pattern != "" {
|
||||
rctx.routePattern = rn.endpoints[method].pattern
|
||||
rctx.RoutePatterns = append(rctx.RoutePatterns, rctx.routePattern)
|
||||
}
|
||||
|
||||
return rn, rn.endpoints, rn.endpoints[method].handler
|
||||
}
|
||||
|
||||
// Recursive edge traversal by checking all nodeTyp groups along the way.
|
||||
// It's like searching through a multi-dimensional radix trie.
|
||||
func (n *node) findRoute(rctx *Context, method methodTyp, path string) *node {
|
||||
nn := n
|
||||
search := path
|
||||
|
||||
for t, nds := range nn.children {
|
||||
ntyp := nodeTyp(t)
|
||||
if len(nds) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var xn *node
|
||||
xsearch := search
|
||||
|
||||
var label byte
|
||||
if search != "" {
|
||||
label = search[0]
|
||||
}
|
||||
|
||||
switch ntyp {
|
||||
case ntStatic:
|
||||
xn = nds.findEdge(label)
|
||||
if xn == nil || !strings.HasPrefix(xsearch, xn.prefix) {
|
||||
continue
|
||||
}
|
||||
xsearch = xsearch[len(xn.prefix):]
|
||||
|
||||
case ntParam, ntRegexp:
|
||||
// short-circuit and return no matching route for empty param values
|
||||
if xsearch == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// serially loop through each node grouped by the tail delimiter
|
||||
for idx := 0; idx < len(nds); idx++ {
|
||||
xn = nds[idx]
|
||||
|
||||
// label for param nodes is the delimiter byte
|
||||
p := strings.IndexByte(xsearch, xn.tail)
|
||||
|
||||
if p < 0 {
|
||||
if xn.tail == '/' {
|
||||
p = len(xsearch)
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else if ntyp == ntRegexp && p == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if ntyp == ntRegexp && xn.rex != nil {
|
||||
if !xn.rex.MatchString(xsearch[:p]) {
|
||||
continue
|
||||
}
|
||||
} else if strings.IndexByte(xsearch[:p], '/') != -1 {
|
||||
// avoid a match across path segments
|
||||
continue
|
||||
}
|
||||
|
||||
prevlen := len(rctx.routeParams.Values)
|
||||
rctx.routeParams.Values = append(rctx.routeParams.Values, xsearch[:p])
|
||||
xsearch = xsearch[p:]
|
||||
|
||||
if len(xsearch) == 0 {
|
||||
if xn.isLeaf() {
|
||||
h := xn.endpoints[method]
|
||||
if h != nil && h.handler != nil {
|
||||
rctx.routeParams.Keys = append(rctx.routeParams.Keys, h.paramKeys...)
|
||||
return xn
|
||||
}
|
||||
|
||||
// flag that the routing context found a route, but not a corresponding
|
||||
// supported method
|
||||
rctx.methodNotAllowed = true
|
||||
}
|
||||
}
|
||||
|
||||
// recursively find the next node on this branch
|
||||
fin := xn.findRoute(rctx, method, xsearch)
|
||||
if fin != nil {
|
||||
return fin
|
||||
}
|
||||
|
||||
// not found on this branch, reset vars
|
||||
rctx.routeParams.Values = rctx.routeParams.Values[:prevlen]
|
||||
xsearch = search
|
||||
}
|
||||
|
||||
rctx.routeParams.Values = append(rctx.routeParams.Values, "")
|
||||
|
||||
default:
|
||||
// catch-all nodes
|
||||
rctx.routeParams.Values = append(rctx.routeParams.Values, search)
|
||||
xn = nds[0]
|
||||
xsearch = ""
|
||||
}
|
||||
|
||||
if xn == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// did we find it yet?
|
||||
if len(xsearch) == 0 {
|
||||
if xn.isLeaf() {
|
||||
h := xn.endpoints[method]
|
||||
if h != nil && h.handler != nil {
|
||||
rctx.routeParams.Keys = append(rctx.routeParams.Keys, h.paramKeys...)
|
||||
return xn
|
||||
}
|
||||
|
||||
// flag that the routing context found a route, but not a corresponding
|
||||
// supported method
|
||||
rctx.methodNotAllowed = true
|
||||
}
|
||||
}
|
||||
|
||||
// recursively find the next node..
|
||||
fin := xn.findRoute(rctx, method, xsearch)
|
||||
if fin != nil {
|
||||
return fin
|
||||
}
|
||||
|
||||
// Did not find final handler, let's remove the param here if it was set
|
||||
if xn.typ > ntStatic {
|
||||
if len(rctx.routeParams.Values) > 0 {
|
||||
rctx.routeParams.Values = rctx.routeParams.Values[:len(rctx.routeParams.Values)-1]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *node) findEdge(ntyp nodeTyp, label byte) *node {
|
||||
nds := n.children[ntyp]
|
||||
num := len(nds)
|
||||
idx := 0
|
||||
|
||||
switch ntyp {
|
||||
case ntStatic, ntParam, ntRegexp:
|
||||
i, j := 0, num-1
|
||||
for i <= j {
|
||||
idx = i + (j-i)/2
|
||||
if label > nds[idx].label {
|
||||
i = idx + 1
|
||||
} else if label < nds[idx].label {
|
||||
j = idx - 1
|
||||
} else {
|
||||
i = num // breaks cond
|
||||
}
|
||||
}
|
||||
if nds[idx].label != label {
|
||||
return nil
|
||||
}
|
||||
return nds[idx]
|
||||
|
||||
default: // catch all
|
||||
return nds[idx]
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) isLeaf() bool {
|
||||
return n.endpoints != nil
|
||||
}
|
||||
|
||||
func (n *node) findPattern(pattern string) bool {
|
||||
nn := n
|
||||
for _, nds := range nn.children {
|
||||
if len(nds) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
n = nn.findEdge(nds[0].typ, pattern[0])
|
||||
if n == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var idx int
|
||||
var xpattern string
|
||||
|
||||
switch n.typ {
|
||||
case ntStatic:
|
||||
idx = longestPrefix(pattern, n.prefix)
|
||||
if idx < len(n.prefix) {
|
||||
continue
|
||||
}
|
||||
|
||||
case ntParam, ntRegexp:
|
||||
idx = strings.IndexByte(pattern, '}') + 1
|
||||
|
||||
case ntCatchAll:
|
||||
idx = longestPrefix(pattern, "*")
|
||||
|
||||
default:
|
||||
panic("chi: unknown node type")
|
||||
}
|
||||
|
||||
xpattern = pattern[idx:]
|
||||
if len(xpattern) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return n.findPattern(xpattern)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (n *node) routes() []Route {
|
||||
rts := []Route{}
|
||||
|
||||
n.walk(func(eps endpoints, subroutes Routes) bool {
|
||||
if eps[mSTUB] != nil && eps[mSTUB].handler != nil && subroutes == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Group methodHandlers by unique patterns
|
||||
pats := make(map[string]endpoints)
|
||||
|
||||
for mt, h := range eps {
|
||||
if h.pattern == "" {
|
||||
continue
|
||||
}
|
||||
p, ok := pats[h.pattern]
|
||||
if !ok {
|
||||
p = endpoints{}
|
||||
pats[h.pattern] = p
|
||||
}
|
||||
p[mt] = h
|
||||
}
|
||||
|
||||
for p, mh := range pats {
|
||||
hs := make(map[string]http.Handler)
|
||||
if mh[mALL] != nil && mh[mALL].handler != nil {
|
||||
hs["*"] = mh[mALL].handler
|
||||
}
|
||||
|
||||
for mt, h := range mh {
|
||||
if h.handler == nil {
|
||||
continue
|
||||
}
|
||||
m := methodTypString(mt)
|
||||
if m == "" {
|
||||
continue
|
||||
}
|
||||
hs[m] = h.handler
|
||||
}
|
||||
|
||||
rt := Route{p, hs, subroutes}
|
||||
rts = append(rts, rt)
|
||||
}
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
return rts
|
||||
}
|
||||
|
||||
func (n *node) walk(fn func(eps endpoints, subroutes Routes) bool) bool {
|
||||
// Visit the leaf values if any
|
||||
if (n.endpoints != nil || n.subroutes != nil) && fn(n.endpoints, n.subroutes) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Recurse on the children
|
||||
for _, ns := range n.children {
|
||||
for _, cn := range ns {
|
||||
if cn.walk(fn) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// patNextSegment returns the next segment details from a pattern:
|
||||
// node type, param key, regexp string, param tail byte, param starting index, param ending index
|
||||
func patNextSegment(pattern string) (nodeTyp, string, string, byte, int, int) {
|
||||
ps := strings.Index(pattern, "{")
|
||||
ws := strings.Index(pattern, "*")
|
||||
|
||||
if ps < 0 && ws < 0 {
|
||||
return ntStatic, "", "", 0, 0, len(pattern) // we return the entire thing
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if ps >= 0 && ws >= 0 && ws < ps {
|
||||
panic("chi: wildcard '*' must be the last pattern in a route, otherwise use a '{param}'")
|
||||
}
|
||||
|
||||
var tail byte = '/' // Default endpoint tail to / byte
|
||||
|
||||
if ps >= 0 {
|
||||
// Param/Regexp pattern is next
|
||||
nt := ntParam
|
||||
|
||||
// Read to closing } taking into account opens and closes in curl count (cc)
|
||||
cc := 0
|
||||
pe := ps
|
||||
for i, c := range pattern[ps:] {
|
||||
if c == '{' {
|
||||
cc++
|
||||
} else if c == '}' {
|
||||
cc--
|
||||
if cc == 0 {
|
||||
pe = ps + i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if pe == ps {
|
||||
panic("chi: route param closing delimiter '}' is missing")
|
||||
}
|
||||
|
||||
key := pattern[ps+1 : pe]
|
||||
pe++ // set end to next position
|
||||
|
||||
if pe < len(pattern) {
|
||||
tail = pattern[pe]
|
||||
}
|
||||
|
||||
var rexpat string
|
||||
if idx := strings.Index(key, ":"); idx >= 0 {
|
||||
nt = ntRegexp
|
||||
rexpat = key[idx+1:]
|
||||
key = key[:idx]
|
||||
}
|
||||
|
||||
if len(rexpat) > 0 {
|
||||
if rexpat[0] != '^' {
|
||||
rexpat = "^" + rexpat
|
||||
}
|
||||
if rexpat[len(rexpat)-1] != '$' {
|
||||
rexpat += "$"
|
||||
}
|
||||
}
|
||||
|
||||
return nt, key, rexpat, tail, ps, pe
|
||||
}
|
||||
|
||||
// Wildcard pattern as finale
|
||||
if ws < len(pattern)-1 {
|
||||
panic("chi: wildcard '*' must be the last value in a route. trim trailing text or use a '{param}' instead")
|
||||
}
|
||||
return ntCatchAll, "*", "", 0, ws, len(pattern)
|
||||
}
|
||||
|
||||
func patParamKeys(pattern string) []string {
|
||||
pat := pattern
|
||||
paramKeys := []string{}
|
||||
for {
|
||||
ptyp, paramKey, _, _, _, e := patNextSegment(pat)
|
||||
if ptyp == ntStatic {
|
||||
return paramKeys
|
||||
}
|
||||
for i := 0; i < len(paramKeys); i++ {
|
||||
if paramKeys[i] == paramKey {
|
||||
panic(fmt.Sprintf("chi: routing pattern '%s' contains duplicate param key, '%s'", pattern, paramKey))
|
||||
}
|
||||
}
|
||||
paramKeys = append(paramKeys, paramKey)
|
||||
pat = pat[e:]
|
||||
}
|
||||
}
|
||||
|
||||
// longestPrefix finds the length of the shared prefix
|
||||
// of two strings
|
||||
func longestPrefix(k1, k2 string) int {
|
||||
max := len(k1)
|
||||
if l := len(k2); l < max {
|
||||
max = l
|
||||
}
|
||||
var i int
|
||||
for i = 0; i < max; i++ {
|
||||
if k1[i] != k2[i] {
|
||||
break
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func methodTypString(method methodTyp) string {
|
||||
for s, t := range methodMap {
|
||||
if method == t {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type nodes []*node
|
||||
|
||||
// Sort the list of nodes by label
|
||||
func (ns nodes) Sort() { sort.Sort(ns); ns.tailSort() }
|
||||
func (ns nodes) Len() int { return len(ns) }
|
||||
func (ns nodes) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] }
|
||||
func (ns nodes) Less(i, j int) bool { return ns[i].label < ns[j].label }
|
||||
|
||||
// tailSort pushes nodes with '/' as the tail to the end of the list for param nodes.
|
||||
// The list order determines the traversal order.
|
||||
func (ns nodes) tailSort() {
|
||||
for i := len(ns) - 1; i >= 0; i-- {
|
||||
if ns[i].typ > ntStatic && ns[i].tail == '/' {
|
||||
ns.Swap(i, len(ns)-1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ns nodes) findEdge(label byte) *node {
|
||||
num := len(ns)
|
||||
idx := 0
|
||||
i, j := 0, num-1
|
||||
for i <= j {
|
||||
idx = i + (j-i)/2
|
||||
if label > ns[idx].label {
|
||||
i = idx + 1
|
||||
} else if label < ns[idx].label {
|
||||
j = idx - 1
|
||||
} else {
|
||||
i = num // breaks cond
|
||||
}
|
||||
}
|
||||
if ns[idx].label != label {
|
||||
return nil
|
||||
}
|
||||
return ns[idx]
|
||||
}
|
||||
|
||||
// Route describes the details of a routing handler.
|
||||
// Handlers map key is an HTTP method
|
||||
type Route struct {
|
||||
Pattern string
|
||||
Handlers map[string]http.Handler
|
||||
SubRoutes Routes
|
||||
}
|
||||
|
||||
// WalkFunc is the type of the function called for each method and route visited by Walk.
|
||||
type WalkFunc func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error
|
||||
|
||||
// Walk walks any router tree that implements Routes interface.
|
||||
func Walk(r Routes, walkFn WalkFunc) error {
|
||||
return walk(r, walkFn, "")
|
||||
}
|
||||
|
||||
func walk(r Routes, walkFn WalkFunc, parentRoute string, parentMw ...func(http.Handler) http.Handler) error {
|
||||
for _, route := range r.Routes() {
|
||||
mws := make([]func(http.Handler) http.Handler, len(parentMw))
|
||||
copy(mws, parentMw)
|
||||
mws = append(mws, r.Middlewares()...)
|
||||
|
||||
if route.SubRoutes != nil {
|
||||
if err := walk(route.SubRoutes, walkFn, parentRoute+route.Pattern, mws...); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
for method, handler := range route.Handlers {
|
||||
if method == "*" {
|
||||
// Ignore a "catchAll" method, since we pass down all the specific methods for each route.
|
||||
continue
|
||||
}
|
||||
|
||||
fullRoute := parentRoute + route.Pattern
|
||||
fullRoute = strings.Replace(fullRoute, "/*/", "/", -1)
|
||||
|
||||
if chain, ok := handler.(*ChainHandler); ok {
|
||||
if err := walkFn(method, fullRoute, chain.Endpoint, append(mws, chain.Middlewares...)...); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := walkFn(method, fullRoute, handler, mws...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
20
vendor/github.com/go-chi/httplog/LICENSE
generated
vendored
Normal file
20
vendor/github.com/go-chi/httplog/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2015-present Peter Kieltyka (https://github.com/pkieltyka).
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
67
vendor/github.com/go-chi/httplog/README.md
generated
vendored
Normal file
67
vendor/github.com/go-chi/httplog/README.md
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
httplog
|
||||
=======
|
||||
|
||||
Small but powerful structured logging package for HTTP request logging in Go.
|
||||
|
||||
## Example
|
||||
|
||||
(see [_example/](./_example/main.go))
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/httplog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Logger
|
||||
logger := httplog.NewLogger("httplog-example", httplog.Options{
|
||||
JSON: true,
|
||||
})
|
||||
|
||||
// Service
|
||||
r := chi.NewRouter()
|
||||
r.Use(httplog.RequestLogger(logger))
|
||||
r.Use(middleware.Heartbeat("/ping"))
|
||||
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("hello world"))
|
||||
})
|
||||
|
||||
r.Get("/panic", func(w http.ResponseWriter, r *http.Request) {
|
||||
panic("oh no")
|
||||
})
|
||||
|
||||
r.Get("/info", func(w http.ResponseWriter, r *http.Request) {
|
||||
oplog := httplog.LogEntry(r.Context())
|
||||
w.Header().Add("Content-Type", "text/plain")
|
||||
oplog.Info().Msg("info here")
|
||||
w.Write([]byte("info here"))
|
||||
})
|
||||
|
||||
r.Get("/warn", func(w http.ResponseWriter, r *http.Request) {
|
||||
oplog := httplog.LogEntry(r.Context())
|
||||
oplog.Warn().Msg("warn here")
|
||||
w.WriteHeader(400)
|
||||
w.Write([]byte("warn here"))
|
||||
})
|
||||
|
||||
r.Get("/err", func(w http.ResponseWriter, r *http.Request) {
|
||||
oplog := httplog.LogEntry(r.Context())
|
||||
oplog.Error().Msg("err here")
|
||||
w.WriteHeader(500)
|
||||
w.Write([]byte("err here"))
|
||||
})
|
||||
|
||||
http.ListenAndServe(":5555", r)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
86
vendor/github.com/go-chi/httplog/config.go
generated
vendored
Normal file
86
vendor/github.com/go-chi/httplog/config.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
package httplog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
var DefaultOptions = Options{
|
||||
LogLevel: "info",
|
||||
LevelFieldName: "level",
|
||||
JSON: false,
|
||||
Concise: false,
|
||||
Tags: nil,
|
||||
SkipHeaders: nil,
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
// LogLevel defines the minimum level of severity that app should log.
|
||||
//
|
||||
// Must be one of: ["trace", "debug", "info", "warn", "error", "critical"]
|
||||
LogLevel string
|
||||
|
||||
// LevelFieldName sets the field name for the log level or severity.
|
||||
// Some providers parse and search for different field names.
|
||||
LevelFieldName string
|
||||
|
||||
// JSON enables structured logging output in json. Make sure to enable this
|
||||
// in production mode so log aggregators can receive data in parsable format.
|
||||
//
|
||||
// In local development mode, its appropriate to set this value to false to
|
||||
// receive pretty output and stacktraces to stdout.
|
||||
JSON bool
|
||||
|
||||
// Concise mode includes fewer log details during the request flow. For example
|
||||
// exluding details like request content length, user-agent and other details.
|
||||
// This is useful if during development your console is too noisy.
|
||||
Concise bool
|
||||
|
||||
// Tags are additional fields included at the root level of all logs.
|
||||
// These can be useful for example the commit hash of a build, or an environment
|
||||
// name like prod/stg/dev
|
||||
Tags map[string]string
|
||||
|
||||
// SkipHeaders are additional headers which are redacted from the logs
|
||||
SkipHeaders []string
|
||||
}
|
||||
|
||||
// Configure will set new global/default options for the httplog and behaviour
|
||||
// of underlying zerolog pkg and its global logger.
|
||||
func Configure(opts Options) {
|
||||
if opts.LogLevel == "" {
|
||||
opts.LogLevel = "info"
|
||||
}
|
||||
|
||||
if opts.LevelFieldName == "" {
|
||||
opts.LevelFieldName = "level"
|
||||
}
|
||||
|
||||
// Pre-downcase all SkipHeaders
|
||||
for i, header := range opts.SkipHeaders {
|
||||
opts.SkipHeaders[i] = strings.ToLower(header)
|
||||
}
|
||||
|
||||
DefaultOptions = opts
|
||||
|
||||
// Config the zerolog global logger
|
||||
logLevel, err := zerolog.ParseLevel(strings.ToLower(opts.LogLevel))
|
||||
if err != nil {
|
||||
fmt.Printf("httplog: error! %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
zerolog.SetGlobalLevel(logLevel)
|
||||
|
||||
zerolog.LevelFieldName = strings.ToLower(opts.LevelFieldName)
|
||||
zerolog.TimestampFieldName = "timestamp"
|
||||
zerolog.TimeFieldFormat = time.RFC3339Nano
|
||||
|
||||
if !opts.JSON {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339})
|
||||
}
|
||||
}
|
||||
248
vendor/github.com/go-chi/httplog/httplog.go
generated
vendored
Normal file
248
vendor/github.com/go-chi/httplog/httplog.go
generated
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
package httplog
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func NewLogger(serviceName string, opts ...Options) zerolog.Logger {
|
||||
if len(opts) > 0 {
|
||||
Configure(opts[0])
|
||||
} else {
|
||||
Configure(DefaultOptions)
|
||||
}
|
||||
logger := log.With().Str("service", strings.ToLower(serviceName))
|
||||
if !DefaultOptions.Concise && len(DefaultOptions.Tags) > 0 {
|
||||
logger = logger.Fields(map[string]interface{}{
|
||||
"tags": DefaultOptions.Tags,
|
||||
})
|
||||
}
|
||||
return logger.Logger()
|
||||
}
|
||||
|
||||
// RequestLogger is an http middleware to log http requests and responses.
|
||||
//
|
||||
// NOTE: for simplicty, RequestLogger automatically makes use of the chi RequestID and
|
||||
// Recoverer middleware.
|
||||
func RequestLogger(logger zerolog.Logger) func(next http.Handler) http.Handler {
|
||||
return chi.Chain(
|
||||
middleware.RequestID,
|
||||
Handler(logger),
|
||||
middleware.Recoverer,
|
||||
).Handler
|
||||
}
|
||||
|
||||
func Handler(logger zerolog.Logger) func(next http.Handler) http.Handler {
|
||||
var f middleware.LogFormatter = &requestLogger{logger}
|
||||
return func(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
entry := f.NewLogEntry(r)
|
||||
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
|
||||
|
||||
buf := newLimitBuffer(512)
|
||||
ww.Tee(buf)
|
||||
|
||||
t1 := time.Now()
|
||||
defer func() {
|
||||
var respBody []byte
|
||||
if ww.Status() >= 400 {
|
||||
respBody, _ = ioutil.ReadAll(buf)
|
||||
}
|
||||
entry.Write(ww.Status(), ww.BytesWritten(), ww.Header(), time.Since(t1), respBody)
|
||||
}()
|
||||
|
||||
next.ServeHTTP(ww, middleware.WithLogEntry(r, entry))
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
}
|
||||
|
||||
type requestLogger struct {
|
||||
Logger zerolog.Logger
|
||||
}
|
||||
|
||||
func (l *requestLogger) NewLogEntry(r *http.Request) middleware.LogEntry {
|
||||
entry := &RequestLoggerEntry{}
|
||||
msg := fmt.Sprintf("Request: %s %s", r.Method, r.URL.Path)
|
||||
entry.Logger = l.Logger.With().Fields(requestLogFields(r, true)).Logger()
|
||||
if !DefaultOptions.Concise {
|
||||
entry.Logger.Info().Fields(requestLogFields(r, DefaultOptions.Concise)).Msgf(msg)
|
||||
}
|
||||
return entry
|
||||
}
|
||||
|
||||
type RequestLoggerEntry struct {
|
||||
Logger zerolog.Logger
|
||||
msg string
|
||||
}
|
||||
|
||||
func (l *RequestLoggerEntry) Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{}) {
|
||||
msg := fmt.Sprintf("Response: %d %s", status, statusLabel(status))
|
||||
if l.msg != "" {
|
||||
msg = fmt.Sprintf("%s - %s", msg, l.msg)
|
||||
}
|
||||
|
||||
responseLog := map[string]interface{}{
|
||||
"status": status,
|
||||
"bytes": bytes,
|
||||
"elapsed": float64(elapsed.Nanoseconds()) / 1000000.0, // in milliseconds
|
||||
}
|
||||
|
||||
if !DefaultOptions.Concise {
|
||||
// Include response header, as well for error status codes (>400) we include
|
||||
// the response body so we may inspect the log message sent back to the client.
|
||||
if status >= 400 {
|
||||
body, _ := extra.([]byte)
|
||||
responseLog["body"] = string(body)
|
||||
}
|
||||
if len(header) > 0 {
|
||||
responseLog["header"] = headerLogField(header)
|
||||
}
|
||||
}
|
||||
|
||||
l.Logger.WithLevel(statusLevel(status)).Fields(map[string]interface{}{
|
||||
"httpResponse": responseLog,
|
||||
}).Msgf(msg)
|
||||
}
|
||||
|
||||
func (l *RequestLoggerEntry) Panic(v interface{}, stack []byte) {
|
||||
stacktrace := "#"
|
||||
if DefaultOptions.JSON {
|
||||
stacktrace = string(stack)
|
||||
}
|
||||
|
||||
l.Logger = l.Logger.With().
|
||||
Str("stacktrace", stacktrace).
|
||||
Str("panic", fmt.Sprintf("%+v", v)).
|
||||
Logger()
|
||||
|
||||
l.msg = fmt.Sprintf("%+v", v)
|
||||
|
||||
if !DefaultOptions.JSON {
|
||||
middleware.PrintPrettyStack(v)
|
||||
}
|
||||
}
|
||||
|
||||
func requestLogFields(r *http.Request, concise bool) map[string]interface{} {
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
requestURL := fmt.Sprintf("%s://%s%s", scheme, r.Host, r.RequestURI)
|
||||
|
||||
requestFields := map[string]interface{}{
|
||||
"requestURL": requestURL,
|
||||
"requestMethod": r.Method,
|
||||
"requestPath": r.URL.Path,
|
||||
"remoteIP": r.RemoteAddr,
|
||||
"proto": r.Proto,
|
||||
}
|
||||
if reqID := middleware.GetReqID(r.Context()); reqID != "" {
|
||||
requestFields["requestID"] = reqID
|
||||
}
|
||||
|
||||
if concise {
|
||||
return map[string]interface{}{
|
||||
"httpRequest": requestFields,
|
||||
}
|
||||
}
|
||||
|
||||
requestFields["scheme"] = scheme
|
||||
|
||||
if len(r.Header) > 0 {
|
||||
requestFields["header"] = headerLogField(r.Header)
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"httpRequest": requestFields,
|
||||
}
|
||||
}
|
||||
|
||||
func headerLogField(header http.Header) map[string]string {
|
||||
headerField := map[string]string{}
|
||||
for k, v := range header {
|
||||
k = strings.ToLower(k)
|
||||
switch {
|
||||
case len(v) == 0:
|
||||
continue
|
||||
case len(v) == 1:
|
||||
headerField[k] = v[0]
|
||||
default:
|
||||
headerField[k] = fmt.Sprintf("[%s]", strings.Join(v, "], ["))
|
||||
}
|
||||
if k == "authorization" || k == "cookie" || k == "set-cookie" {
|
||||
headerField[k] = "***"
|
||||
}
|
||||
|
||||
for _, skip := range DefaultOptions.SkipHeaders {
|
||||
if k == skip {
|
||||
headerField[k] = "***"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return headerField
|
||||
}
|
||||
|
||||
func statusLevel(status int) zerolog.Level {
|
||||
switch {
|
||||
case status <= 0:
|
||||
return zerolog.WarnLevel
|
||||
case status < 400: // for codes in 100s, 200s, 300s
|
||||
return zerolog.InfoLevel
|
||||
case status >= 400 && status < 500:
|
||||
return zerolog.WarnLevel
|
||||
case status >= 500:
|
||||
return zerolog.ErrorLevel
|
||||
default:
|
||||
return zerolog.InfoLevel
|
||||
}
|
||||
}
|
||||
|
||||
func statusLabel(status int) string {
|
||||
switch {
|
||||
case status >= 100 && status < 300:
|
||||
return "OK"
|
||||
case status >= 300 && status < 400:
|
||||
return "Redirect"
|
||||
case status >= 400 && status < 500:
|
||||
return "Client Error"
|
||||
case status >= 500:
|
||||
return "Server Error"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// Helper methods used by the application to get the request-scoped
|
||||
// logger entry and set additional fields between handlers.
|
||||
//
|
||||
// This is a useful pattern to use to set state on the entry as it
|
||||
// passes through the handler chain, which at any point can be logged
|
||||
// with a call to .Print(), .Info(), etc.
|
||||
|
||||
func LogEntry(ctx context.Context) zerolog.Logger {
|
||||
entry := ctx.Value(middleware.LogEntryCtxKey).(*RequestLoggerEntry)
|
||||
return entry.Logger
|
||||
}
|
||||
|
||||
func LogEntrySetField(ctx context.Context, key, value string) {
|
||||
if entry, ok := ctx.Value(middleware.LogEntryCtxKey).(*RequestLoggerEntry); ok {
|
||||
entry.Logger = entry.Logger.With().Str(key, value).Logger()
|
||||
}
|
||||
}
|
||||
|
||||
func LogEntrySetFields(ctx context.Context, fields map[string]interface{}) {
|
||||
if entry, ok := ctx.Value(middleware.LogEntryCtxKey).(*RequestLoggerEntry); ok {
|
||||
entry.Logger = entry.Logger.With().Fields(fields).Logger()
|
||||
}
|
||||
}
|
||||
37
vendor/github.com/go-chi/httplog/util.go
generated
vendored
Normal file
37
vendor/github.com/go-chi/httplog/util.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package httplog
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
// limitBuffer is used to pipe response body information from the
|
||||
// response writer to a certain limit amount. The idea is to read
|
||||
// a portion of the response body such as an error response so we
|
||||
// may log it.
|
||||
type limitBuffer struct {
|
||||
*bytes.Buffer
|
||||
limit int
|
||||
}
|
||||
|
||||
func newLimitBuffer(size int) io.ReadWriter {
|
||||
return limitBuffer{
|
||||
Buffer: bytes.NewBuffer(make([]byte, 0, size)),
|
||||
limit: size,
|
||||
}
|
||||
}
|
||||
|
||||
func (b limitBuffer) Write(p []byte) (n int, err error) {
|
||||
if b.Buffer.Len() >= b.limit {
|
||||
return len(p), nil
|
||||
}
|
||||
limit := b.limit
|
||||
if len(p) < limit {
|
||||
limit = len(p)
|
||||
}
|
||||
return b.Buffer.Write(p[:limit])
|
||||
}
|
||||
|
||||
func (b limitBuffer) Read(p []byte) (n int, err error) {
|
||||
return b.Buffer.Read(p)
|
||||
}
|
||||
3
vendor/github.com/go-toast/toast/.gitignore
generated
vendored
Normal file
3
vendor/github.com/go-toast/toast/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.idea/
|
||||
vendor/*
|
||||
!vendor/vendor.json
|
||||
7
vendor/github.com/go-toast/toast/LICENSE
generated
vendored
Normal file
7
vendor/github.com/go-toast/toast/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
Copyright (c) 2016 Jacob Marshall
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
61
vendor/github.com/go-toast/toast/readme.md
generated
vendored
Normal file
61
vendor/github.com/go-toast/toast/readme.md
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
# Toast
|
||||
|
||||
A go package for Windows 10 toast notifications.
|
||||
|
||||
As seen in [jacobmarshall/pokevision-cli](https://github.com/jacobmarshall/pokevision-cli).
|
||||
|
||||
## CLI
|
||||
|
||||
As well as using go-toast within your Go projects, you can also utilise the CLI - for any of your projects.
|
||||
|
||||
Download [64bit](https://go-toast-downloads.s3.amazonaws.com/v1/toast64.exe) or [32bit](https://go-toast-downloads.s3.amazonaws.com/v1/toast32.exe)
|
||||
|
||||
```cmd
|
||||
C:\Users\Example\Downloads\toast64.exe \
|
||||
--app-id "Example App" \
|
||||
--title "Hello World" \
|
||||
--message "Lorem ipsum dolor sit amet, consectetur adipiscing elit." \
|
||||
--icon "C:\Users\Example\Pictures\icon.png" \
|
||||
--audio "default" --loop \
|
||||
--duration "long" \
|
||||
--activation-arg "https://google.com" \
|
||||
--action "Open maps" --action-arg "bingmaps:?q=sushi" \
|
||||
--action "Open browser" --action-arg "http://..."
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"gopkg.in/toast.v1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
notification := toast.Notification{
|
||||
AppID: "Example App",
|
||||
Title: "My notification",
|
||||
Message: "Some message about how important something is...",
|
||||
Icon: "go.png", // This file must exist (remove this line if it doesn't)
|
||||
Actions: []toast.Action{
|
||||
{"protocol", "I'm a button", ""},
|
||||
{"protocol", "Me too!", ""},
|
||||
},
|
||||
}
|
||||
err := notification.Push()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||
|
||||

|
||||
BIN
vendor/github.com/go-toast/toast/screenshot-action-centre.png
generated
vendored
Normal file
BIN
vendor/github.com/go-toast/toast/screenshot-action-centre.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
BIN
vendor/github.com/go-toast/toast/screenshot-cli.png
generated
vendored
Normal file
BIN
vendor/github.com/go-toast/toast/screenshot-cli.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
BIN
vendor/github.com/go-toast/toast/screenshot-toast.png
generated
vendored
Normal file
BIN
vendor/github.com/go-toast/toast/screenshot-toast.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
359
vendor/github.com/go-toast/toast/toast.go
generated
vendored
Normal file
359
vendor/github.com/go-toast/toast/toast.go
generated
vendored
Normal file
@@ -0,0 +1,359 @@
|
||||
package toast
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/nu7hatch/gouuid"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var toastTemplate *template.Template
|
||||
|
||||
var (
|
||||
ErrorInvalidAudio error = errors.New("toast: invalid audio")
|
||||
ErrorInvalidDuration = errors.New("toast: invalid duration")
|
||||
)
|
||||
|
||||
type toastAudio string
|
||||
|
||||
const (
|
||||
Default toastAudio = "ms-winsoundevent:Notification.Default"
|
||||
IM = "ms-winsoundevent:Notification.IM"
|
||||
Mail = "ms-winsoundevent:Notification.Mail"
|
||||
Reminder = "ms-winsoundevent:Notification.Reminder"
|
||||
SMS = "ms-winsoundevent:Notification.SMS"
|
||||
LoopingAlarm = "ms-winsoundevent:Notification.Looping.Alarm"
|
||||
LoopingAlarm2 = "ms-winsoundevent:Notification.Looping.Alarm2"
|
||||
LoopingAlarm3 = "ms-winsoundevent:Notification.Looping.Alarm3"
|
||||
LoopingAlarm4 = "ms-winsoundevent:Notification.Looping.Alarm4"
|
||||
LoopingAlarm5 = "ms-winsoundevent:Notification.Looping.Alarm5"
|
||||
LoopingAlarm6 = "ms-winsoundevent:Notification.Looping.Alarm6"
|
||||
LoopingAlarm7 = "ms-winsoundevent:Notification.Looping.Alarm7"
|
||||
LoopingAlarm8 = "ms-winsoundevent:Notification.Looping.Alarm8"
|
||||
LoopingAlarm9 = "ms-winsoundevent:Notification.Looping.Alarm9"
|
||||
LoopingAlarm10 = "ms-winsoundevent:Notification.Looping.Alarm10"
|
||||
LoopingCall = "ms-winsoundevent:Notification.Looping.Call"
|
||||
LoopingCall2 = "ms-winsoundevent:Notification.Looping.Call2"
|
||||
LoopingCall3 = "ms-winsoundevent:Notification.Looping.Call3"
|
||||
LoopingCall4 = "ms-winsoundevent:Notification.Looping.Call4"
|
||||
LoopingCall5 = "ms-winsoundevent:Notification.Looping.Call5"
|
||||
LoopingCall6 = "ms-winsoundevent:Notification.Looping.Call6"
|
||||
LoopingCall7 = "ms-winsoundevent:Notification.Looping.Call7"
|
||||
LoopingCall8 = "ms-winsoundevent:Notification.Looping.Call8"
|
||||
LoopingCall9 = "ms-winsoundevent:Notification.Looping.Call9"
|
||||
LoopingCall10 = "ms-winsoundevent:Notification.Looping.Call10"
|
||||
Silent = "silent"
|
||||
)
|
||||
|
||||
type toastDuration string
|
||||
|
||||
const (
|
||||
Short toastDuration = "short"
|
||||
Long = "long"
|
||||
)
|
||||
|
||||
func init() {
|
||||
toastTemplate = template.New("toast")
|
||||
toastTemplate.Parse(`
|
||||
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
|
||||
[Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
|
||||
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
|
||||
|
||||
$APP_ID = '{{if .AppID}}{{.AppID}}{{else}}Windows App{{end}}'
|
||||
|
||||
$template = @"
|
||||
<toast activationType="{{.ActivationType}}" launch="{{.ActivationArguments}}" duration="{{.Duration}}">
|
||||
<visual>
|
||||
<binding template="ToastGeneric">
|
||||
{{if .Icon}}
|
||||
<image placement="appLogoOverride" src="{{.Icon}}" />
|
||||
{{end}}
|
||||
{{if .Title}}
|
||||
<text><![CDATA[{{.Title}}]]></text>
|
||||
{{end}}
|
||||
{{if .Message}}
|
||||
<text><![CDATA[{{.Message}}]]></text>
|
||||
{{end}}
|
||||
</binding>
|
||||
</visual>
|
||||
{{if ne .Audio "silent"}}
|
||||
<audio src="{{.Audio}}" loop="{{.Loop}}" />
|
||||
{{else}}
|
||||
<audio silent="true" />
|
||||
{{end}}
|
||||
{{if .Actions}}
|
||||
<actions>
|
||||
{{range .Actions}}
|
||||
<action activationType="{{.Type}}" content="{{.Label}}" arguments="{{.Arguments}}" />
|
||||
{{end}}
|
||||
</actions>
|
||||
{{end}}
|
||||
</toast>
|
||||
"@
|
||||
|
||||
$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
|
||||
$xml.LoadXml($template)
|
||||
$toast = New-Object Windows.UI.Notifications.ToastNotification $xml
|
||||
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($APP_ID).Show($toast)
|
||||
`)
|
||||
}
|
||||
|
||||
// Notification
|
||||
//
|
||||
// The toast notification data. The following fields are strongly recommended;
|
||||
// - AppID
|
||||
// - Title
|
||||
//
|
||||
// If no toastAudio is provided, then the toast notification will be silent.
|
||||
// You can set the toast to have a default audio by setting "Audio" to "toast.Default", or if your go app takes
|
||||
// user-provided input for audio, call the "toast.Audio(name)" func.
|
||||
//
|
||||
// The AppID is shown beneath the toast message (in certain cases), and above the notification within the Action
|
||||
// Center - and is used to group your notifications together. It is recommended that you provide a "pretty"
|
||||
// name for your app, and not something like "com.example.MyApp".
|
||||
//
|
||||
// If no Title is provided, but a Message is, the message will display as the toast notification's title -
|
||||
// which is a slightly different font style (heavier).
|
||||
//
|
||||
// The Icon should be an absolute path to the icon (as the toast is invoked from a temporary path on the user's
|
||||
// system, not the working directory).
|
||||
//
|
||||
// If you would like the toast to call an external process/open a webpage, then you can set ActivationArguments
|
||||
// to the uri you would like to trigger when the toast is clicked. For example: "https://google.com" would open
|
||||
// the Google homepage when the user clicks the toast notification.
|
||||
// By default, clicking the toast just hides/dismisses it.
|
||||
//
|
||||
// The following would show a notification to the user letting them know they received an email, and opens
|
||||
// gmail.com when they click the notification. It also makes the Windows 10 "mail" sound effect.
|
||||
//
|
||||
// toast := toast.Notification{
|
||||
// AppID: "Google Mail",
|
||||
// Title: email.Subject,
|
||||
// Message: email.Preview,
|
||||
// Icon: "C:/Program Files/Google Mail/icons/logo.png",
|
||||
// ActivationArguments: "https://gmail.com",
|
||||
// Audio: toast.Mail,
|
||||
// }
|
||||
//
|
||||
// err := toast.Push()
|
||||
type Notification struct {
|
||||
// The name of your app. This value shows up in Windows 10's Action Centre, so make it
|
||||
// something readable for your users. It can contain spaces, however special characters
|
||||
// (eg. é) are not supported.
|
||||
AppID string
|
||||
|
||||
// The main title/heading for the toast notification.
|
||||
Title string
|
||||
|
||||
// The single/multi line message to display for the toast notification.
|
||||
Message string
|
||||
|
||||
// An optional path to an image on the OS to display to the left of the title & message.
|
||||
Icon string
|
||||
|
||||
// The type of notification level action (like toast.Action)
|
||||
ActivationType string
|
||||
|
||||
// The activation/action arguments (invoked when the user clicks the notification)
|
||||
ActivationArguments string
|
||||
|
||||
// Optional action buttons to display below the notification title & message.
|
||||
Actions []Action
|
||||
|
||||
// The audio to play when displaying the toast
|
||||
Audio toastAudio
|
||||
|
||||
// Whether to loop the audio (default false)
|
||||
Loop bool
|
||||
|
||||
// How long the toast should show up for (short/long)
|
||||
Duration toastDuration
|
||||
}
|
||||
|
||||
// Action
|
||||
//
|
||||
// Defines an actionable button.
|
||||
// See https://msdn.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-adaptive-interactive-toasts for more info.
|
||||
//
|
||||
// Only protocol type action buttons are actually useful, as there's no way of receiving feedback from the
|
||||
// user's choice. Examples of protocol type action buttons include: "bingmaps:?q=sushi" to open up Windows 10's
|
||||
// maps app with a pre-populated search field set to "sushi".
|
||||
//
|
||||
// toast.Action{"protocol", "Open Maps", "bingmaps:?q=sushi"}
|
||||
type Action struct {
|
||||
Type string
|
||||
Label string
|
||||
Arguments string
|
||||
}
|
||||
|
||||
func (n *Notification) applyDefaults() {
|
||||
if n.ActivationType == "" {
|
||||
n.ActivationType = "protocol"
|
||||
}
|
||||
if n.Duration == "" {
|
||||
n.Duration = Short
|
||||
}
|
||||
if n.Audio == "" {
|
||||
n.Audio = Default
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Notification) buildXML() (string, error) {
|
||||
var out bytes.Buffer
|
||||
err := toastTemplate.Execute(&out, n)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return out.String(), nil
|
||||
}
|
||||
|
||||
// Builds the Windows PowerShell script & invokes it, causing the toast to display.
|
||||
//
|
||||
// Note: Running the PowerShell script is by far the slowest process here, and can take a few
|
||||
// seconds in some cases.
|
||||
//
|
||||
// notification := toast.Notification{
|
||||
// AppID: "Example App",
|
||||
// Title: "My notification",
|
||||
// Message: "Some message about how important something is...",
|
||||
// Icon: "go.png",
|
||||
// Actions: []toast.Action{
|
||||
// {"protocol", "I'm a button", ""},
|
||||
// {"protocol", "Me too!", ""},
|
||||
// },
|
||||
// }
|
||||
// err := notification.Push()
|
||||
// if err != nil {
|
||||
// log.Fatalln(err)
|
||||
// }
|
||||
func (n *Notification) Push() error {
|
||||
n.applyDefaults()
|
||||
xml, err := n.buildXML()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return invokeTemporaryScript(xml)
|
||||
}
|
||||
|
||||
// Returns a toastAudio given a user-provided input (useful for cli apps).
|
||||
//
|
||||
// If the "name" doesn't match, then the default toastAudio is returned, along with ErrorInvalidAudio.
|
||||
//
|
||||
// The following names are valid;
|
||||
// - default
|
||||
// - im
|
||||
// - mail
|
||||
// - reminder
|
||||
// - sms
|
||||
// - loopingalarm
|
||||
// - loopimgalarm[2-10]
|
||||
// - loopingcall
|
||||
// - loopingcall[2-10]
|
||||
// - silent
|
||||
//
|
||||
// Handle the error appropriately according to how your app should work.
|
||||
func Audio(name string) (toastAudio, error) {
|
||||
switch strings.ToLower(name) {
|
||||
case "default":
|
||||
return Default, nil
|
||||
case "im":
|
||||
return IM, nil
|
||||
case "mail":
|
||||
return Mail, nil
|
||||
case "reminder":
|
||||
return Reminder, nil
|
||||
case "sms":
|
||||
return SMS, nil
|
||||
case "loopingalarm":
|
||||
return LoopingAlarm, nil
|
||||
case "loopingalarm2":
|
||||
return LoopingAlarm2, nil
|
||||
case "loopingalarm3":
|
||||
return LoopingAlarm3, nil
|
||||
case "loopingalarm4":
|
||||
return LoopingAlarm4, nil
|
||||
case "loopingalarm5":
|
||||
return LoopingAlarm5, nil
|
||||
case "loopingalarm6":
|
||||
return LoopingAlarm6, nil
|
||||
case "loopingalarm7":
|
||||
return LoopingAlarm7, nil
|
||||
case "loopingalarm8":
|
||||
return LoopingAlarm8, nil
|
||||
case "loopingalarm9":
|
||||
return LoopingAlarm9, nil
|
||||
case "loopingalarm10":
|
||||
return LoopingAlarm10, nil
|
||||
case "loopingcall":
|
||||
return LoopingCall, nil
|
||||
case "loopingcall2":
|
||||
return LoopingCall2, nil
|
||||
case "loopingcall3":
|
||||
return LoopingCall3, nil
|
||||
case "loopingcall4":
|
||||
return LoopingCall4, nil
|
||||
case "loopingcall5":
|
||||
return LoopingCall5, nil
|
||||
case "loopingcall6":
|
||||
return LoopingCall6, nil
|
||||
case "loopingcall7":
|
||||
return LoopingCall7, nil
|
||||
case "loopingcall8":
|
||||
return LoopingCall8, nil
|
||||
case "loopingcall9":
|
||||
return LoopingCall9, nil
|
||||
case "loopingcall10":
|
||||
return LoopingCall10, nil
|
||||
case "silent":
|
||||
return Silent, nil
|
||||
default:
|
||||
return Default, ErrorInvalidAudio
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a toastDuration given a user-provided input (useful for cli apps).
|
||||
//
|
||||
// The default duration is short. If the "name" doesn't match, then the default toastDuration is returned,
|
||||
// along with ErrorInvalidDuration. Most of the time "short" is the most appropriate for a toast notification,
|
||||
// and Microsoft recommend not using "long", but it can be useful for important dialogs or looping sound toasts.
|
||||
//
|
||||
// The following names are valid;
|
||||
// - short
|
||||
// - long
|
||||
//
|
||||
// Handle the error appropriately according to how your app should work.
|
||||
func Duration(name string) (toastDuration, error) {
|
||||
switch strings.ToLower(name) {
|
||||
case "short":
|
||||
return Short, nil
|
||||
case "long":
|
||||
return Long, nil
|
||||
default:
|
||||
return Short, ErrorInvalidDuration
|
||||
}
|
||||
}
|
||||
|
||||
func invokeTemporaryScript(content string) error {
|
||||
id, _ := uuid.NewV4()
|
||||
file := filepath.Join(os.TempDir(), id.String()+".ps1")
|
||||
defer os.Remove(file)
|
||||
bomUtf8 := []byte{0xEF, 0xBB, 0xBF}
|
||||
out := append(bomUtf8, []byte(content)...)
|
||||
err := ioutil.WriteFile(file, out, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd := exec.Command("PowerShell", "-ExecutionPolicy", "Bypass", "-File", file)
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
||||
if err = cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
22
vendor/github.com/kermieisinthehouse/gosx-notifier/LICENSE-MIT
generated
vendored
Normal file
22
vendor/github.com/kermieisinthehouse/gosx-notifier/LICENSE-MIT
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
Copyright (c) 2012 Ralph Caraveo
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
179
vendor/github.com/kermieisinthehouse/gosx-notifier/README.md
generated
vendored
Normal file
179
vendor/github.com/kermieisinthehouse/gosx-notifier/README.md
generated
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
gosx-notifier
|
||||
===========================
|
||||
A [Go](http://golang.org) lib for sending desktop notifications to OSX Mountain Lion's (10.8 or higher REQUIRED)
|
||||
[Notification Center](http://www.macworld.com/article/1165411/mountain_lion_hands_on_with_notification_center.html).
|
||||
|
||||
[](http://godoc.org/github.com/deckarep/gosx-notifier)
|
||||
|
||||
Update 4/3/2014
|
||||
------
|
||||
On OSX 10.9 and above gosx-notifier now supports images and icons.
|
||||

|
||||
|
||||
Synopsis
|
||||
--------
|
||||
OSX Mountain Lion comes packaged with a built-in notification center. For whatever reason, [Apple sandboxed the
|
||||
notification center API](http://forums.macrumors.com/showthread.php?t=1403807) to apps hosted in its App Store. The end
|
||||
result? A potentially useful API shackled to Apple's ecosystem.
|
||||
|
||||
Thankfully, [Eloy Durán](https://github.com/alloy) put together [an osx app](https://github.com/alloy/terminal-notifier) that allows terminal access to the sandboxed API. **gosx-notifier** embeds this app with a simple interface to the closed API.
|
||||
|
||||
It's not perfect, and the implementor will quickly notice its limitations. However, it's a start and any pull requests are accepted and encouraged!
|
||||
|
||||
Dependencies:
|
||||
-------------
|
||||
There are none! If you utilize this package and create a binary executable it will auto-magically install the terminal-notifier component into a temp directory of the server. This is possible because in this latest version the terminal-notifier binary is now statically embedded into the Go source files.
|
||||
|
||||
|
||||
Installation and Requirements
|
||||
-----------------------------
|
||||
The following command will install the notification api for Go along with the binaries. Also, utilizing this lib requires OSX 10.8 or higher. It will simply not work on lower versions of OSX.
|
||||
|
||||
```sh
|
||||
go get github.com/deckarep/gosx-notifier
|
||||
```
|
||||
|
||||
Using the Command Line
|
||||
-------------
|
||||
```Go
|
||||
notify "Wow! A notification!!!"
|
||||
```
|
||||
|
||||
useful for knowing when long running commands finish
|
||||
|
||||
```Go
|
||||
longRunningCommand && notify done!
|
||||
```
|
||||
|
||||
Using the Code
|
||||
------------------
|
||||
It's a pretty straightforward API:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/deckarep/gosx-notifier"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//At a minimum specifiy a message to display to end-user.
|
||||
note := gosxnotifier.NewNotification("Check your Apple Stock!")
|
||||
|
||||
//Optionally, set a title
|
||||
note.Title = "It's money making time 💰"
|
||||
|
||||
//Optionally, set a subtitle
|
||||
note.Subtitle = "My subtitle"
|
||||
|
||||
//Optionally, set a sound from a predefined set.
|
||||
note.Sound = gosxnotifier.Basso
|
||||
|
||||
//Optionally, set a group which ensures only one notification is ever shown replacing previous notification of same group id.
|
||||
note.Group = "com.unique.yourapp.identifier"
|
||||
|
||||
//Optionally, set a sender (Notification will now use the Safari icon)
|
||||
note.Sender = "com.apple.Safari"
|
||||
|
||||
//Optionally, specifiy a url or bundleid to open should the notification be
|
||||
//clicked.
|
||||
note.Link = "http://www.yahoo.com" //or BundleID like: com.apple.Terminal
|
||||
|
||||
//Optionally, an app icon (10.9+ ONLY)
|
||||
note.AppIcon = "gopher.png"
|
||||
|
||||
//Optionally, a content image (10.9+ ONLY)
|
||||
note.ContentImage = "gopher.png"
|
||||
|
||||
//Then, push the notification
|
||||
err := note.Push()
|
||||
|
||||
//If necessary, check error
|
||||
if err != nil {
|
||||
log.Println("Uh oh!")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Sample App: Desktop Pinger Notification - monitors your websites and will notifiy you when a website is down.
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/deckarep/gosx-notifier"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//a slice of string sites that you are interested in watching
|
||||
var sites []string = []string{
|
||||
"http://www.yahoo.com",
|
||||
"http://www.google.com",
|
||||
"http://www.bing.com"}
|
||||
|
||||
func main() {
|
||||
ch := make(chan string)
|
||||
|
||||
for _, s := range sites {
|
||||
go pinger(ch, s)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case result := <-ch:
|
||||
if strings.HasPrefix(result, "-") {
|
||||
s := strings.Trim(result, "-")
|
||||
showNotification("Urgent, can't ping website: " + s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func showNotification(message string) {
|
||||
|
||||
note := gosxnotifier.NewNotification(message)
|
||||
note.Title = "Site Down"
|
||||
note.Sound = gosxnotifier.Default
|
||||
|
||||
note.Push()
|
||||
}
|
||||
|
||||
//Prefixing a site with a + means it's up, while - means it's down
|
||||
func pinger(ch chan string, site string) {
|
||||
for {
|
||||
res, err := http.Get(site)
|
||||
|
||||
if err != nil {
|
||||
ch <- "-" + site
|
||||
} else {
|
||||
if res.StatusCode != 200 {
|
||||
ch <- "-" + site
|
||||
} else {
|
||||
ch <- "+" + site
|
||||
}
|
||||
res.Body.Close()
|
||||
}
|
||||
time.Sleep(30 * time.Second)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Usage Ideas
|
||||
-----------
|
||||
* Monitor your awesome server cluster and push notifications when something goes haywire (we've all been there)
|
||||
* Scrape Hacker News looking for articles of certain keywords and push a notification
|
||||
* Monitor your stock performance, push a notification, before you lose all your money
|
||||
* Hook it up to ifttt.com and push a notification when your motion-sensor at home goes off
|
||||
|
||||
Coming Soon
|
||||
-----------
|
||||
* Remove ID
|
||||
|
||||
Licence
|
||||
-------
|
||||
This project is dual licensed under [any licensing defined by the underlying apps](https://github.com/alloy/terminal-notifier) and MIT licensed for this version written in Go.
|
||||
|
||||
|
||||
[](https://bitdeli.com/free "Bitdeli Badge")
|
||||
BIN
vendor/github.com/kermieisinthehouse/gosx-notifier/example.png
generated
vendored
Normal file
BIN
vendor/github.com/kermieisinthehouse/gosx-notifier/example.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
BIN
vendor/github.com/kermieisinthehouse/gosx-notifier/gopher.png
generated
vendored
Normal file
BIN
vendor/github.com/kermieisinthehouse/gosx-notifier/gopher.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
137
vendor/github.com/kermieisinthehouse/gosx-notifier/gosx-notifier.go
generated
vendored
Normal file
137
vendor/github.com/kermieisinthehouse/gosx-notifier/gosx-notifier.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
package gosxnotifier
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Sound string
|
||||
|
||||
const (
|
||||
Default Sound = "'default'"
|
||||
Basso Sound = "Basso"
|
||||
Blow Sound = "Blow"
|
||||
Bottle Sound = "Bottle"
|
||||
Frog Sound = "Frog"
|
||||
Funk Sound = "Funk"
|
||||
Glass Sound = "Glass"
|
||||
Hero Sound = "Hero"
|
||||
Morse Sound = "Morse"
|
||||
Ping Sound = "Ping"
|
||||
Pop Sound = "Pop"
|
||||
Purr Sound = "Purr"
|
||||
Sosumi Sound = "Sosumi"
|
||||
Submarine Sound = "Submarine"
|
||||
Tink Sound = "Tink"
|
||||
)
|
||||
|
||||
type Notification struct {
|
||||
Message string //required
|
||||
Title string //optional
|
||||
Subtitle string //optional
|
||||
Sound Sound //optional
|
||||
Link string //optional
|
||||
Sender string //optional
|
||||
Group string //optional
|
||||
AppIcon string //optional
|
||||
ContentImage string //optional
|
||||
}
|
||||
|
||||
func NewNotification(message string) *Notification {
|
||||
n := &Notification{Message: message}
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *Notification) Push() error {
|
||||
if supportedOS() {
|
||||
commandTuples := make([]string, 0)
|
||||
|
||||
//check required commands
|
||||
if n.Message == "" {
|
||||
return errors.New("Please specifiy a proper message argument.")
|
||||
} else {
|
||||
commandTuples = append(commandTuples, []string{"-message", n.Message}...)
|
||||
}
|
||||
|
||||
//add title if found
|
||||
if n.Title != "" {
|
||||
commandTuples = append(commandTuples, []string{"-title", n.Title}...)
|
||||
}
|
||||
|
||||
//add subtitle if found
|
||||
if n.Subtitle != "" {
|
||||
commandTuples = append(commandTuples, []string{"-subtitle", n.Subtitle}...)
|
||||
}
|
||||
|
||||
//add sound if specified
|
||||
if n.Sound != "" {
|
||||
commandTuples = append(commandTuples, []string{"-sound", string(n.Sound)}...)
|
||||
}
|
||||
|
||||
//add group if specified
|
||||
if n.Group != "" {
|
||||
commandTuples = append(commandTuples, []string{"-group", n.Group}...)
|
||||
}
|
||||
|
||||
//add appIcon if specified
|
||||
if n.AppIcon != "" {
|
||||
img, err := normalizeImagePath(n.AppIcon)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
commandTuples = append(commandTuples, []string{"-appIcon", img}...)
|
||||
}
|
||||
|
||||
//add contentImage if specified
|
||||
if n.ContentImage != "" {
|
||||
img, err := normalizeImagePath(n.ContentImage)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commandTuples = append(commandTuples, []string{"-contentImage", img}...)
|
||||
}
|
||||
|
||||
//add url if specified
|
||||
url, err := url.Parse(n.Link)
|
||||
if err != nil {
|
||||
n.Link = ""
|
||||
}
|
||||
if url != nil && n.Link != "" {
|
||||
commandTuples = append(commandTuples, []string{"-open", n.Link}...)
|
||||
}
|
||||
|
||||
//add bundle id if specified
|
||||
if strings.HasPrefix(strings.ToLower(n.Link), "com.") {
|
||||
commandTuples = append(commandTuples, []string{"-activate", n.Link}...)
|
||||
}
|
||||
|
||||
//add sender if specified
|
||||
if strings.HasPrefix(strings.ToLower(n.Sender), "com.") {
|
||||
commandTuples = append(commandTuples, []string{"-sender", n.Sender}...)
|
||||
}
|
||||
|
||||
if len(commandTuples) == 0 {
|
||||
return errors.New("Please provide a Message and Type at a minimum.")
|
||||
}
|
||||
|
||||
_, err = exec.Command(FinalPath, commandTuples...).Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeImagePath(image string) (string, error) {
|
||||
if imagePath, err := filepath.Abs(image); err != nil {
|
||||
return "", errors.New("Could not resolve image path of image: " + image)
|
||||
} else {
|
||||
return imagePath, nil
|
||||
}
|
||||
}
|
||||
3428
vendor/github.com/kermieisinthehouse/gosx-notifier/terminal-app-binary.go
generated
vendored
Normal file
3428
vendor/github.com/kermieisinthehouse/gosx-notifier/terminal-app-binary.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
116
vendor/github.com/kermieisinthehouse/gosx-notifier/terminal-app-zip.go
generated
vendored
Normal file
116
vendor/github.com/kermieisinthehouse/gosx-notifier/terminal-app-zip.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
package gosxnotifier
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
const (
|
||||
zipPath = "terminal-notifier.temp.zip"
|
||||
executablePath = "terminal-notifier.app/Contents/MacOS/terminal-notifier"
|
||||
tempDirSuffix = "gosxnotifier"
|
||||
)
|
||||
|
||||
var (
|
||||
rootPath string
|
||||
FinalPath string
|
||||
)
|
||||
|
||||
func supportedOS() bool {
|
||||
if runtime.GOOS == "darwin" {
|
||||
return true
|
||||
} else {
|
||||
log.Print("OS does not support terminal-notifier")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
if supportedOS() {
|
||||
err := installTerminalNotifier()
|
||||
if err != nil {
|
||||
log.Fatalf("Could not install Terminal Notifier to a temp directory: %s", err)
|
||||
} else {
|
||||
FinalPath = filepath.Join(rootPath, executablePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func exists(file string) bool {
|
||||
if _, err := os.Stat(file); os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func installTerminalNotifier() error {
|
||||
rootPath = filepath.Join(os.TempDir(), tempDirSuffix)
|
||||
|
||||
//if terminal-notifier.app already installed no-need to re-install
|
||||
if exists(filepath.Join(rootPath, executablePath)) {
|
||||
return nil
|
||||
}
|
||||
buf := bytes.NewReader(terminalnotifier())
|
||||
reader, err := zip.NewReader(buf, int64(buf.Len()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = unpackZip(reader, rootPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not unpack zip terminal-notifier file: %s", err)
|
||||
}
|
||||
|
||||
err = os.Chmod(filepath.Join(rootPath, executablePath), 0755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not make terminal-notifier executable: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func unpackZip(reader *zip.Reader, tempPath string) error {
|
||||
for _, zipFile := range reader.File {
|
||||
name := zipFile.Name
|
||||
mode := zipFile.Mode()
|
||||
if mode.IsDir() {
|
||||
if err := os.MkdirAll(filepath.Join(tempPath, name), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := unpackZippedFile(name, tempPath, zipFile); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func unpackZippedFile(filename, tempPath string, zipFile *zip.File) error {
|
||||
writer, err := os.Create(filepath.Join(tempPath, filename))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer writer.Close()
|
||||
|
||||
reader, err := zipFile.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer reader.Close()
|
||||
|
||||
if _, err = io.Copy(writer, reader); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
12
vendor/github.com/kermieisinthehouse/systray/.gitignore
generated
vendored
Normal file
12
vendor/github.com/kermieisinthehouse/systray/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
example/example
|
||||
webview_example/webview_example
|
||||
*~
|
||||
*.swp
|
||||
**/*.exe
|
||||
Release
|
||||
Debug
|
||||
*.sdf
|
||||
dll/systray_unsigned.dll
|
||||
out.txt
|
||||
.vs
|
||||
on_exit*.txt
|
||||
125
vendor/github.com/kermieisinthehouse/systray/CHANGELOG.md
generated
vendored
Normal file
125
vendor/github.com/kermieisinthehouse/systray/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
# Changelog
|
||||
|
||||
## [v1.1.0](https://github.com/getlantern/systray/tree/v1.1.0) (2020-11-18)
|
||||
|
||||
[Full Changelog](https://github.com/getlantern/systray/compare/v1.0.5...v1.1.0)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Add submenu support for Linux [\#183](https://github.com/getlantern/systray/pull/183) ([fbrinker](https://github.com/fbrinker))
|
||||
- Add checkbox support for Linux [\#181](https://github.com/getlantern/systray/pull/181) ([fbrinker](https://github.com/fbrinker))
|
||||
- fix SetTitle documentation [\#179](https://github.com/getlantern/systray/pull/179) ([delthas](https://github.com/delthas))
|
||||
|
||||
## [v1.0.5](https://github.com/getlantern/systray/tree/v1.0.5) (2020-10-19)
|
||||
|
||||
[Full Changelog](https://github.com/getlantern/systray/compare/v1.0.4...v1.0.5)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- start menu ID with positive, and change the type to uint32 [\#173](https://github.com/getlantern/systray/pull/173) ([joesis](https://github.com/joesis))
|
||||
- Allows disabling items in submenu on macOS [\#172](https://github.com/getlantern/systray/pull/172) ([joesis](https://github.com/joesis))
|
||||
- Does not use the template icon for regular icons [\#171](https://github.com/getlantern/systray/pull/171) ([sithembiso](https://github.com/sithembiso))
|
||||
|
||||
## [v1.0.4](https://github.com/getlantern/systray/tree/v1.0.4) (2020-07-21)
|
||||
|
||||
[Full Changelog](https://github.com/getlantern/systray/compare/1.0.3...v1.0.4)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- protect shared data structures with proper mutexes [\#162](https://github.com/getlantern/systray/pull/162) ([joesis](https://github.com/joesis))
|
||||
|
||||
## [1.0.3](https://github.com/getlantern/systray/tree/1.0.3) (2020-06-11)
|
||||
|
||||
[Full Changelog](https://github.com/getlantern/systray/compare/v1.0.3...1.0.3)
|
||||
|
||||
## [v1.0.3](https://github.com/getlantern/systray/tree/v1.0.3) (2020-06-11)
|
||||
|
||||
[Full Changelog](https://github.com/getlantern/systray/compare/v1.0.2...v1.0.3)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- have a workaround to avoid crash on old macOS versions [\#153](https://github.com/getlantern/systray/pull/153) ([joesis](https://github.com/joesis))
|
||||
- Fix bug on darwin of setting icon for menu [\#147](https://github.com/getlantern/systray/pull/147) ([mangalaman93](https://github.com/mangalaman93))
|
||||
|
||||
## [v1.0.2](https://github.com/getlantern/systray/tree/v1.0.2) (2020-05-19)
|
||||
|
||||
[Full Changelog](https://github.com/getlantern/systray/compare/v1.0.1...v1.0.2)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- remove unused dependencies [\#145](https://github.com/getlantern/systray/pull/145) ([joesis](https://github.com/joesis))
|
||||
|
||||
## [v1.0.1](https://github.com/getlantern/systray/tree/v1.0.1) (2020-05-18)
|
||||
|
||||
[Full Changelog](https://github.com/getlantern/systray/compare/1.0.1...v1.0.1)
|
||||
|
||||
## [1.0.1](https://github.com/getlantern/systray/tree/1.0.1) (2020-05-18)
|
||||
|
||||
[Full Changelog](https://github.com/getlantern/systray/compare/1.0.0...1.0.1)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Unlock menuItemsLock before changing UI [\#144](https://github.com/getlantern/systray/pull/144) ([joesis](https://github.com/joesis))
|
||||
|
||||
## [1.0.0](https://github.com/getlantern/systray/tree/1.0.0) (2020-05-18)
|
||||
|
||||
[Full Changelog](https://github.com/getlantern/systray/compare/v1.0.0...1.0.0)
|
||||
|
||||
## [v1.0.0](https://github.com/getlantern/systray/tree/v1.0.0) (2020-05-18)
|
||||
|
||||
[Full Changelog](https://github.com/getlantern/systray/compare/0.9.0...v1.0.0)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Check if the menu item is nil [\#137](https://github.com/getlantern/systray/pull/137) ([myleshorton](https://github.com/myleshorton))
|
||||
|
||||
## [0.9.0](https://github.com/getlantern/systray/tree/0.9.0) (2020-03-24)
|
||||
|
||||
[Full Changelog](https://github.com/getlantern/systray/compare/v0.9.0...0.9.0)
|
||||
|
||||
## [v0.9.0](https://github.com/getlantern/systray/tree/v0.9.0) (2020-03-24)
|
||||
|
||||
[Full Changelog](https://github.com/getlantern/systray/compare/8e63b37ef27d94f6db79c4ffb941608e8f0dc2f9...v0.9.0)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Backport all features and fixes from master [\#140](https://github.com/getlantern/systray/pull/140) ([joesis](https://github.com/joesis))
|
||||
- Nested menu windows [\#132](https://github.com/getlantern/systray/pull/132) ([joesis](https://github.com/joesis))
|
||||
- Support for nested sub-menus on OS X [\#131](https://github.com/getlantern/systray/pull/131) ([oxtoacart](https://github.com/oxtoacart))
|
||||
- Use temp directory for walk resource manager [\#129](https://github.com/getlantern/systray/pull/129) ([max-b](https://github.com/max-b))
|
||||
- Added support for template icons on macOS [\#119](https://github.com/getlantern/systray/pull/119) ([oxtoacart](https://github.com/oxtoacart))
|
||||
- When launching app window on macOS, make application a foreground app… [\#118](https://github.com/getlantern/systray/pull/118) ([oxtoacart](https://github.com/oxtoacart))
|
||||
- Include stdlib.h in systray\_browser\_linux to explicitly declare funct… [\#114](https://github.com/getlantern/systray/pull/114) ([oxtoacart](https://github.com/oxtoacart))
|
||||
- Fix panic when resources root path is not the working directory [\#112](https://github.com/getlantern/systray/pull/112) ([ksubileau](https://github.com/ksubileau))
|
||||
- Don't print close reason to console [\#111](https://github.com/getlantern/systray/pull/111) ([ksubileau](https://github.com/ksubileau))
|
||||
- Systray icon could not be changed dynamically [\#110](https://github.com/getlantern/systray/pull/110) ([ksubileau](https://github.com/ksubileau))
|
||||
- Preventing deadlock on menu item ClickeCh when no one is listening, c… [\#105](https://github.com/getlantern/systray/pull/105) ([oxtoacart](https://github.com/oxtoacart))
|
||||
- Reverted deadlock fix \(Affected other receivers\) [\#104](https://github.com/getlantern/systray/pull/104) ([ldstein](https://github.com/ldstein))
|
||||
- Fix Deadlock and item ordering in Windows [\#103](https://github.com/getlantern/systray/pull/103) ([ldstein](https://github.com/ldstein))
|
||||
- Minor README improvements \(go modules, example app, screenshot\) [\#98](https://github.com/getlantern/systray/pull/98) ([tstromberg](https://github.com/tstromberg))
|
||||
- Add support for app window [\#97](https://github.com/getlantern/systray/pull/97) ([oxtoacart](https://github.com/oxtoacart))
|
||||
- systray\_darwin.m: Compare Mac OS min version with value instead of macro [\#94](https://github.com/getlantern/systray/pull/94) ([teddywing](https://github.com/teddywing))
|
||||
- Attempt to fix https://github.com/getlantern/systray/issues/75 [\#92](https://github.com/getlantern/systray/pull/92) ([mikeschinkel](https://github.com/mikeschinkel))
|
||||
- Fix application path for MacOS in README [\#91](https://github.com/getlantern/systray/pull/91) ([zereraz](https://github.com/zereraz))
|
||||
- Document cross-platform console window details [\#81](https://github.com/getlantern/systray/pull/81) ([michaelsanford](https://github.com/michaelsanford))
|
||||
- Fix bad-looking system tray icon in Windows [\#78](https://github.com/getlantern/systray/pull/78) ([juja256](https://github.com/juja256))
|
||||
- Add the separator to the visible items [\#76](https://github.com/getlantern/systray/pull/76) ([meskio](https://github.com/meskio))
|
||||
- keep track of hidden items [\#74](https://github.com/getlantern/systray/pull/74) ([kalikaneko](https://github.com/kalikaneko))
|
||||
- Support macOS older than 10.13 [\#73](https://github.com/getlantern/systray/pull/73) ([swznd](https://github.com/swznd))
|
||||
- define ERROR\_SUCCESS as syscall.Errno [\#69](https://github.com/getlantern/systray/pull/69) ([joesis](https://github.com/joesis))
|
||||
- Bug/fix broken menuitem show [\#68](https://github.com/getlantern/systray/pull/68) ([kalikaneko](https://github.com/kalikaneko))
|
||||
- Fix mac deprecations [\#66](https://github.com/getlantern/systray/pull/66) ([jefvel](https://github.com/jefvel))
|
||||
- Made it possible to add icons to menu items on Mac [\#65](https://github.com/getlantern/systray/pull/65) ([jefvel](https://github.com/jefvel))
|
||||
- linux: delete temp files as soon as they are not needed [\#63](https://github.com/getlantern/systray/pull/63) ([meskio](https://github.com/meskio))
|
||||
- Merge changes from amkulikov to remove DLL for windows [\#56](https://github.com/getlantern/systray/pull/56) ([oxtoacart](https://github.com/oxtoacart))
|
||||
- Revert "Use templated icons for the menu bar in macOS" [\#51](https://github.com/getlantern/systray/pull/51) ([stoggi](https://github.com/stoggi))
|
||||
- Use templated icons for the menu bar in macOS [\#46](https://github.com/getlantern/systray/pull/46) ([stoggi](https://github.com/stoggi))
|
||||
- Syscalls instead of custom DLLs [\#44](https://github.com/getlantern/systray/pull/44) ([amkulikov](https://github.com/amkulikov))
|
||||
- On quit exit main loop on linux [\#41](https://github.com/getlantern/systray/pull/41) ([meskio](https://github.com/meskio))
|
||||
- Fixed hide show in linux \(\#37\) [\#39](https://github.com/getlantern/systray/pull/39) ([meskio](https://github.com/meskio))
|
||||
- fix: linux compilation warning [\#36](https://github.com/getlantern/systray/pull/36) ([novln](https://github.com/novln))
|
||||
- Added separator functionality [\#32](https://github.com/getlantern/systray/pull/32) ([oxtoacart](https://github.com/oxtoacart))
|
||||
|
||||
|
||||
|
||||
\* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
|
||||
202
vendor/github.com/kermieisinthehouse/systray/LICENSE
generated
vendored
Normal file
202
vendor/github.com/kermieisinthehouse/systray/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014 Brave New Software Project, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
18
vendor/github.com/kermieisinthehouse/systray/Makefile
generated
vendored
Normal file
18
vendor/github.com/kermieisinthehouse/systray/Makefile
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
tag-changelog: require-version require-gh-token
|
||||
echo "Tagging..." && \
|
||||
git tag -a "$$VERSION" -f --annotate -m"Tagged $$VERSION" && \
|
||||
git push --tags -f && \
|
||||
git checkout master && \
|
||||
git pull && \
|
||||
github_changelog_generator --no-issues --max-issues 100 --token "${GH_TOKEN}" --user getlantern --project systray && \
|
||||
git add CHANGELOG.md && \
|
||||
git commit -m "Updated changelog for $$VERSION" && \
|
||||
git push origin HEAD && \
|
||||
git checkout -
|
||||
|
||||
guard-%:
|
||||
@ if [ -z '${${*}}' ]; then echo 'Environment variable $* not set' && exit 1; fi
|
||||
|
||||
require-version: guard-VERSION
|
||||
|
||||
require-gh-token: guard-GH_TOKEN
|
||||
122
vendor/github.com/kermieisinthehouse/systray/README.md
generated
vendored
Normal file
122
vendor/github.com/kermieisinthehouse/systray/README.md
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
systray is a cross-platform Go library to place an icon and menu in the notification area.
|
||||
|
||||
This is a fork of the abandoned https://github.com/getlantern/systray with pull requests reviewed and merged, and bugs fixed.
|
||||
|
||||
## Features
|
||||
|
||||
* Supported on Windows, macOS, and Linux
|
||||
* Menu items can be checked and/or disabled
|
||||
* Methods may be called from any Goroutine
|
||||
|
||||
## API
|
||||
|
||||
```go
|
||||
func main() {
|
||||
systray.Run(onReady, onExit)
|
||||
}
|
||||
|
||||
func onReady() {
|
||||
systray.SetIcon(icon.Data)
|
||||
systray.SetTitle("Awesome App")
|
||||
systray.SetTooltip("Pretty awesome超级棒")
|
||||
mQuit := systray.AddMenuItem("Quit", "Quit the whole app")
|
||||
|
||||
// Sets the icon of a menu item. Only available on Mac and Windows.
|
||||
mQuit.SetIcon(icon.Data)
|
||||
}
|
||||
|
||||
func onExit() {
|
||||
// clean up here
|
||||
}
|
||||
```
|
||||
|
||||
See [full API](https://pkg.go.dev/github.com/getlantern/systray?tab=doc) as well as [CHANGELOG](https://github.com/getlantern/systray/tree/master/CHANGELOG.md).
|
||||
|
||||
## Try the example app!
|
||||
|
||||
Have go v1.12+ or higher installed? Here's an example to get started on macOS:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/getlantern/systray
|
||||
cd example
|
||||
env GO111MODULE=on go build
|
||||
./example
|
||||
```
|
||||
|
||||
On Windows, you should build like this:
|
||||
|
||||
```
|
||||
env GO111MODULE=on go build -ldflags "-H=windowsgui"
|
||||
```
|
||||
|
||||
The following text will then appear on the console:
|
||||
|
||||
|
||||
```sh
|
||||
go: finding github.com/skratchdot/open-golang latest
|
||||
go: finding github.com/getlantern/systray latest
|
||||
go: finding github.com/getlantern/golog latest
|
||||
```
|
||||
|
||||
Now look for *Awesome App* in your menu bar!
|
||||
|
||||

|
||||
|
||||
## The Webview example
|
||||
|
||||
The code under `webview_example` is to demostrate how it can co-exist with other UI elements. Note that the example doesn't work on macOS versions older than 10.15 Catalina.
|
||||
|
||||
## Platform notes
|
||||
|
||||
### Linux
|
||||
|
||||
* Building apps requires gcc as well as the `gtk3` and `libayatana-appindicator` development headers to be installed. For Debian or Ubuntu, you may install these using:
|
||||
|
||||
```sh
|
||||
sudo apt-get install gcc libgtk-3-dev libappindicator3-dev
|
||||
```
|
||||
|
||||
On Linux Mint, `libxapp-dev` is also required .
|
||||
|
||||
To build `webview_example`, you also need to install `libwebkit2gtk-4.0-dev` and remove `webview_example/rsrc.syso` which is required on Windows.
|
||||
|
||||
### Windows
|
||||
|
||||
* To avoid opening a console at application startup, use these compile flags:
|
||||
|
||||
```sh
|
||||
go build -ldflags -H=windowsgui
|
||||
```
|
||||
|
||||
### macOS
|
||||
|
||||
On macOS, you will need to create an application bundle to wrap the binary; simply folders with the following minimal structure and assets:
|
||||
|
||||
```
|
||||
SystrayApp.app/
|
||||
Contents/
|
||||
Info.plist
|
||||
MacOS/
|
||||
go-executable
|
||||
Resources/
|
||||
SystrayApp.icns
|
||||
```
|
||||
|
||||
When running as an app bundle, you may want to add one or both of the following to your Info.plist:
|
||||
|
||||
```xml
|
||||
<!-- avoid having a blurry icon and text -->
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<string>True</string>
|
||||
|
||||
<!-- avoid showing the app on the Dock -->
|
||||
<key>LSUIElement</key>
|
||||
<string>1</string>
|
||||
```
|
||||
|
||||
Consult the [Official Apple Documentation here](https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW1).
|
||||
|
||||
## Credits
|
||||
|
||||
- https://github.com/xilp/systray
|
||||
- https://github.com/cratonica/trayhost
|
||||
244
vendor/github.com/kermieisinthehouse/systray/systray.go
generated
vendored
Normal file
244
vendor/github.com/kermieisinthehouse/systray/systray.go
generated
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
Package systray is a cross-platform Go library to place an icon and menu in the notification area.
|
||||
*/
|
||||
package systray
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
var (
|
||||
systrayReady func()
|
||||
systrayExit func()
|
||||
menuItems = make(map[uint32]*MenuItem)
|
||||
menuItemsLock sync.RWMutex
|
||||
|
||||
currentID = uint32(0)
|
||||
quitOnce sync.Once
|
||||
)
|
||||
|
||||
func init() {
|
||||
runtime.LockOSThread()
|
||||
}
|
||||
|
||||
// MenuItem is used to keep track each menu item of systray.
|
||||
// Don't create it directly, use the one systray.AddMenuItem() returned
|
||||
type MenuItem struct {
|
||||
// ClickedCh is the channel which will be notified when the menu item is clicked
|
||||
ClickedCh chan struct{}
|
||||
|
||||
// id uniquely identify a menu item, not supposed to be modified
|
||||
id uint32
|
||||
// title is the text shown on menu item
|
||||
title string
|
||||
// tooltip is the text shown when pointing to menu item
|
||||
tooltip string
|
||||
// disabled menu item is grayed out and has no effect when clicked
|
||||
disabled bool
|
||||
// checked menu item has a tick before the title
|
||||
checked bool
|
||||
// has the menu item a checkbox (Linux)
|
||||
isCheckable bool
|
||||
// parent item, for sub menus
|
||||
parent *MenuItem
|
||||
}
|
||||
|
||||
func (item *MenuItem) String() string {
|
||||
if item.parent == nil {
|
||||
return fmt.Sprintf("MenuItem[%d, %q]", item.id, item.title)
|
||||
}
|
||||
return fmt.Sprintf("MenuItem[%d, parent %d, %q]", item.id, item.parent.id, item.title)
|
||||
}
|
||||
|
||||
// newMenuItem returns a populated MenuItem object
|
||||
func newMenuItem(title string, tooltip string, parent *MenuItem) *MenuItem {
|
||||
return &MenuItem{
|
||||
ClickedCh: make(chan struct{}),
|
||||
id: atomic.AddUint32(¤tID, 1),
|
||||
title: title,
|
||||
tooltip: tooltip,
|
||||
disabled: false,
|
||||
checked: false,
|
||||
isCheckable: false,
|
||||
parent: parent,
|
||||
}
|
||||
}
|
||||
|
||||
// Run initializes GUI and starts the event loop, then invokes the onReady
|
||||
// callback. It blocks until systray.Quit() is called.
|
||||
func Run(onReady func(), onExit func()) {
|
||||
Register(onReady, onExit)
|
||||
nativeLoop()
|
||||
}
|
||||
|
||||
// Register initializes GUI and registers the callbacks but relies on the
|
||||
// caller to run the event loop somewhere else. It's useful if the program
|
||||
// needs to show other UI elements, for example, webview.
|
||||
// To overcome some OS weirdness, On macOS versions before Catalina, calling
|
||||
// this does exactly the same as Run().
|
||||
func Register(onReady func(), onExit func()) {
|
||||
if onReady == nil {
|
||||
systrayReady = func() {}
|
||||
} else {
|
||||
// Run onReady on separate goroutine to avoid blocking event loop
|
||||
readyCh := make(chan interface{})
|
||||
go func() {
|
||||
<-readyCh
|
||||
onReady()
|
||||
}()
|
||||
systrayReady = func() {
|
||||
close(readyCh)
|
||||
}
|
||||
}
|
||||
// unlike onReady, onExit runs in the event loop to make sure it has time to
|
||||
// finish before the process terminates
|
||||
if onExit == nil {
|
||||
onExit = func() {}
|
||||
}
|
||||
systrayExit = onExit
|
||||
registerSystray()
|
||||
}
|
||||
|
||||
// Quit the systray
|
||||
func Quit() {
|
||||
quitOnce.Do(quit)
|
||||
}
|
||||
|
||||
// AddMenuItem adds a menu item with the designated title and tooltip.
|
||||
// It can be safely invoked from different goroutines.
|
||||
// Created menu items are checkable on Windows and OSX by default. For Linux you have to use AddMenuItemCheckbox
|
||||
func AddMenuItem(title string, tooltip string) *MenuItem {
|
||||
item := newMenuItem(title, tooltip, nil)
|
||||
item.update()
|
||||
return item
|
||||
}
|
||||
|
||||
// AddMenuItemCheckbox adds a menu item with the designated title and tooltip and a checkbox for Linux.
|
||||
// It can be safely invoked from different goroutines.
|
||||
// On Windows and OSX this is the same as calling AddMenuItem
|
||||
func AddMenuItemCheckbox(title string, tooltip string, checked bool) *MenuItem {
|
||||
item := newMenuItem(title, tooltip, nil)
|
||||
item.isCheckable = true
|
||||
item.checked = checked
|
||||
item.update()
|
||||
return item
|
||||
}
|
||||
|
||||
// AddSeparator adds a separator bar to the menu
|
||||
func AddSeparator() {
|
||||
addSeparator(atomic.AddUint32(¤tID, 1))
|
||||
}
|
||||
|
||||
// AddSubMenuItem adds a nested sub-menu item with the designated title and tooltip.
|
||||
// It can be safely invoked from different goroutines.
|
||||
// Created menu items are checkable on Windows and OSX by default. For Linux you have to use AddSubMenuItemCheckbox
|
||||
func (item *MenuItem) AddSubMenuItem(title string, tooltip string) *MenuItem {
|
||||
child := newMenuItem(title, tooltip, item)
|
||||
child.update()
|
||||
return child
|
||||
}
|
||||
|
||||
// AddSubMenuItemCheckbox adds a nested sub-menu item with the designated title and tooltip and a checkbox for Linux.
|
||||
// It can be safely invoked from different goroutines.
|
||||
// On Windows and OSX this is the same as calling AddSubMenuItem
|
||||
func (item *MenuItem) AddSubMenuItemCheckbox(title string, tooltip string, checked bool) *MenuItem {
|
||||
child := newMenuItem(title, tooltip, item)
|
||||
child.isCheckable = true
|
||||
child.checked = checked
|
||||
child.update()
|
||||
return child
|
||||
}
|
||||
|
||||
// SetTitle set the text to display on a menu item
|
||||
func (item *MenuItem) SetTitle(title string) {
|
||||
item.title = title
|
||||
item.update()
|
||||
}
|
||||
|
||||
// Title returns the text displayed on a menu item
|
||||
func (item *MenuItem) Title() string {
|
||||
return item.title
|
||||
}
|
||||
|
||||
// SetTooltip set the tooltip to show when mouse hover
|
||||
func (item *MenuItem) SetTooltip(tooltip string) {
|
||||
item.tooltip = tooltip
|
||||
item.update()
|
||||
}
|
||||
|
||||
// Tooltip returns the tooltip shown when mouse hover
|
||||
func (item *MenuItem) Tooltip() string {
|
||||
return item.tooltip
|
||||
}
|
||||
|
||||
// Disabled checks if the menu item is disabled
|
||||
func (item *MenuItem) Disabled() bool {
|
||||
return item.disabled
|
||||
}
|
||||
|
||||
// Enable a menu item regardless if it's previously enabled or not
|
||||
func (item *MenuItem) Enable() {
|
||||
item.disabled = false
|
||||
item.update()
|
||||
}
|
||||
|
||||
// Disable a menu item regardless if it's previously disabled or not
|
||||
func (item *MenuItem) Disable() {
|
||||
item.disabled = true
|
||||
item.update()
|
||||
}
|
||||
|
||||
// Hide hides a menu item
|
||||
func (item *MenuItem) Hide() {
|
||||
hideMenuItem(item)
|
||||
}
|
||||
|
||||
// Show shows a previously hidden menu item
|
||||
func (item *MenuItem) Show() {
|
||||
showMenuItem(item)
|
||||
}
|
||||
|
||||
// Checked returns if the menu item has a check mark
|
||||
func (item *MenuItem) Checked() bool {
|
||||
return item.checked
|
||||
}
|
||||
|
||||
// Check a menu item regardless if it's previously checked or not
|
||||
func (item *MenuItem) Check() {
|
||||
item.checked = true
|
||||
item.update()
|
||||
}
|
||||
|
||||
// Uncheck a menu item regardless if it's previously unchecked or not
|
||||
func (item *MenuItem) Uncheck() {
|
||||
item.checked = false
|
||||
item.update()
|
||||
}
|
||||
|
||||
// update propagates changes on a menu item to systray
|
||||
func (item *MenuItem) update() {
|
||||
menuItemsLock.Lock()
|
||||
menuItems[item.id] = item
|
||||
menuItemsLock.Unlock()
|
||||
addOrUpdateMenuItem(item)
|
||||
}
|
||||
|
||||
func systrayMenuItemSelected(id uint32) {
|
||||
menuItemsLock.RLock()
|
||||
item, ok := menuItems[id]
|
||||
menuItemsLock.RUnlock()
|
||||
if !ok {
|
||||
log.Printf("No menu item with ID %v", id)
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case item.ClickedCh <- struct{}{}:
|
||||
// in case no one waiting for the channel
|
||||
default:
|
||||
}
|
||||
}
|
||||
17
vendor/github.com/kermieisinthehouse/systray/systray.h
generated
vendored
Normal file
17
vendor/github.com/kermieisinthehouse/systray/systray.h
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "stdbool.h"
|
||||
|
||||
extern void systray_ready();
|
||||
extern void systray_on_exit();
|
||||
extern void systray_menu_item_selected(int menu_id);
|
||||
void registerSystray(void);
|
||||
int nativeLoop(void);
|
||||
|
||||
void setIcon(const char* iconBytes, int length, bool template);
|
||||
void setMenuItemIcon(const char* iconBytes, int length, int menuId, bool template);
|
||||
void setTitle(char* title);
|
||||
void setTooltip(char* tooltip);
|
||||
void add_or_update_menu_item(int menuId, int parentMenuId, char* title, char* tooltip, short disabled, short checked, short isCheckable);
|
||||
void add_separator(int menuId);
|
||||
void hide_menu_item(int menuId);
|
||||
void show_menu_item(int menuId);
|
||||
void quit();
|
||||
38
vendor/github.com/kermieisinthehouse/systray/systray_darwin.go
generated
vendored
Normal file
38
vendor/github.com/kermieisinthehouse/systray/systray_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package systray
|
||||
|
||||
/*
|
||||
#cgo darwin CFLAGS: -DDARWIN -x objective-c -fobjc-arc
|
||||
#cgo darwin LDFLAGS: -framework Cocoa -framework WebKit
|
||||
|
||||
#include "systray.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// SetTemplateIcon sets the systray icon as a template icon (on Mac), falling back
|
||||
// to a regular icon on other platforms.
|
||||
// templateIconBytes and regularIconBytes should be the content of .ico for windows and
|
||||
// .ico/.jpg/.png for other platforms.
|
||||
func SetTemplateIcon(templateIconBytes []byte, regularIconBytes []byte) {
|
||||
cstr := (*C.char)(unsafe.Pointer(&templateIconBytes[0]))
|
||||
C.setIcon(cstr, (C.int)(len(templateIconBytes)), true)
|
||||
}
|
||||
|
||||
// SetIcon sets the icon of a menu item. Only works on macOS and Windows.
|
||||
// iconBytes should be the content of .ico/.jpg/.png
|
||||
func (item *MenuItem) SetIcon(iconBytes []byte) {
|
||||
cstr := (*C.char)(unsafe.Pointer(&iconBytes[0]))
|
||||
C.setMenuItemIcon(cstr, (C.int)(len(iconBytes)), C.int(item.id), false)
|
||||
}
|
||||
|
||||
// SetTemplateIcon sets the icon of a menu item as a template icon (on macOS). On Windows, it
|
||||
// falls back to the regular icon bytes and on Linux it does nothing.
|
||||
// templateIconBytes and regularIconBytes should be the content of .ico for windows and
|
||||
// .ico/.jpg/.png for other platforms.
|
||||
func (item *MenuItem) SetTemplateIcon(templateIconBytes []byte, regularIconBytes []byte) {
|
||||
cstr := (*C.char)(unsafe.Pointer(&templateIconBytes[0]))
|
||||
C.setMenuItemIcon(cstr, (C.int)(len(templateIconBytes)), C.int(item.id), true)
|
||||
}
|
||||
294
vendor/github.com/kermieisinthehouse/systray/systray_darwin.m
generated
vendored
Normal file
294
vendor/github.com/kermieisinthehouse/systray/systray_darwin.m
generated
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include "systray.h"
|
||||
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101400
|
||||
|
||||
#ifndef NSControlStateValueOff
|
||||
#define NSControlStateValueOff NSOffState
|
||||
#endif
|
||||
|
||||
#ifndef NSControlStateValueOn
|
||||
#define NSControlStateValueOn NSOnState
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@interface MenuItem : NSObject
|
||||
{
|
||||
@public
|
||||
NSNumber* menuId;
|
||||
NSNumber* parentMenuId;
|
||||
NSString* title;
|
||||
NSString* tooltip;
|
||||
short disabled;
|
||||
short checked;
|
||||
}
|
||||
-(id) initWithId: (int)theMenuId
|
||||
withParentMenuId: (int)theParentMenuId
|
||||
withTitle: (const char*)theTitle
|
||||
withTooltip: (const char*)theTooltip
|
||||
withDisabled: (short)theDisabled
|
||||
withChecked: (short)theChecked;
|
||||
@end
|
||||
@implementation MenuItem
|
||||
-(id) initWithId: (int)theMenuId
|
||||
withParentMenuId: (int)theParentMenuId
|
||||
withTitle: (const char*)theTitle
|
||||
withTooltip: (const char*)theTooltip
|
||||
withDisabled: (short)theDisabled
|
||||
withChecked: (short)theChecked
|
||||
{
|
||||
menuId = [NSNumber numberWithInt:theMenuId];
|
||||
parentMenuId = [NSNumber numberWithInt:theParentMenuId];
|
||||
title = [[NSString alloc] initWithCString:theTitle
|
||||
encoding:NSUTF8StringEncoding];
|
||||
tooltip = [[NSString alloc] initWithCString:theTooltip
|
||||
encoding:NSUTF8StringEncoding];
|
||||
disabled = theDisabled;
|
||||
checked = theChecked;
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface AppDelegate: NSObject <NSApplicationDelegate>
|
||||
- (void) add_or_update_menu_item:(MenuItem*) item;
|
||||
- (IBAction)menuHandler:(id)sender;
|
||||
@property (assign) IBOutlet NSWindow *window;
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
{
|
||||
NSStatusItem *statusItem;
|
||||
NSMenu *menu;
|
||||
NSCondition* cond;
|
||||
}
|
||||
|
||||
@synthesize window = _window;
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
self->statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
|
||||
self->menu = [[NSMenu alloc] init];
|
||||
[self->menu setAutoenablesItems: FALSE];
|
||||
[self->statusItem setMenu:self->menu];
|
||||
systray_ready();
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
{
|
||||
systray_on_exit();
|
||||
}
|
||||
|
||||
- (void)setIcon:(NSImage *)image {
|
||||
statusItem.button.image = image;
|
||||
[self updateTitleButtonStyle];
|
||||
}
|
||||
|
||||
- (void)setTitle:(NSString *)title {
|
||||
statusItem.button.title = title;
|
||||
[self updateTitleButtonStyle];
|
||||
}
|
||||
|
||||
-(void)updateTitleButtonStyle {
|
||||
if (statusItem.button.image != nil) {
|
||||
if ([statusItem.button.title length] == 0) {
|
||||
statusItem.button.imagePosition = NSImageOnly;
|
||||
} else {
|
||||
statusItem.button.imagePosition = NSImageLeft;
|
||||
}
|
||||
} else {
|
||||
statusItem.button.imagePosition = NSNoImage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)setTooltip:(NSString *)tooltip {
|
||||
statusItem.button.toolTip = tooltip;
|
||||
}
|
||||
|
||||
- (IBAction)menuHandler:(id)sender
|
||||
{
|
||||
NSNumber* menuId = [sender representedObject];
|
||||
systray_menu_item_selected(menuId.intValue);
|
||||
}
|
||||
|
||||
- (void)add_or_update_menu_item:(MenuItem *)item {
|
||||
NSMenu *theMenu = self->menu;
|
||||
NSMenuItem *parentItem;
|
||||
if ([item->parentMenuId integerValue] > 0) {
|
||||
parentItem = find_menu_item(menu, item->parentMenuId);
|
||||
if (parentItem.hasSubmenu) {
|
||||
theMenu = parentItem.submenu;
|
||||
} else {
|
||||
theMenu = [[NSMenu alloc] init];
|
||||
[theMenu setAutoenablesItems:NO];
|
||||
[parentItem setSubmenu:theMenu];
|
||||
}
|
||||
}
|
||||
|
||||
NSMenuItem *menuItem;
|
||||
menuItem = find_menu_item(theMenu, item->menuId);
|
||||
if (menuItem == NULL) {
|
||||
menuItem = [theMenu addItemWithTitle:item->title
|
||||
action:@selector(menuHandler:)
|
||||
keyEquivalent:@""];
|
||||
[menuItem setRepresentedObject:item->menuId];
|
||||
}
|
||||
[menuItem setTitle:item->title];
|
||||
[menuItem setTag:[item->menuId integerValue]];
|
||||
[menuItem setTarget:self];
|
||||
[menuItem setToolTip:item->tooltip];
|
||||
if (item->disabled == 1) {
|
||||
menuItem.enabled = FALSE;
|
||||
} else {
|
||||
menuItem.enabled = TRUE;
|
||||
}
|
||||
if (item->checked == 1) {
|
||||
menuItem.state = NSControlStateValueOn;
|
||||
} else {
|
||||
menuItem.state = NSControlStateValueOff;
|
||||
}
|
||||
}
|
||||
|
||||
NSMenuItem *find_menu_item(NSMenu *ourMenu, NSNumber *menuId) {
|
||||
NSMenuItem *foundItem = [ourMenu itemWithTag:[menuId integerValue]];
|
||||
if (foundItem != NULL) {
|
||||
return foundItem;
|
||||
}
|
||||
NSArray *menu_items = ourMenu.itemArray;
|
||||
int i;
|
||||
for (i = 0; i < [menu_items count]; i++) {
|
||||
NSMenuItem *i_item = [menu_items objectAtIndex:i];
|
||||
if (i_item.hasSubmenu) {
|
||||
foundItem = find_menu_item(i_item.submenu, menuId);
|
||||
if (foundItem != NULL) {
|
||||
return foundItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
};
|
||||
|
||||
- (void) add_separator:(NSNumber*) menuId
|
||||
{
|
||||
[menu addItem: [NSMenuItem separatorItem]];
|
||||
}
|
||||
|
||||
- (void) hide_menu_item:(NSNumber*) menuId
|
||||
{
|
||||
NSMenuItem* menuItem = find_menu_item(menu, menuId);
|
||||
if (menuItem != NULL) {
|
||||
[menuItem setHidden:TRUE];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) setMenuItemIcon:(NSArray*)imageAndMenuId {
|
||||
NSImage* image = [imageAndMenuId objectAtIndex:0];
|
||||
NSNumber* menuId = [imageAndMenuId objectAtIndex:1];
|
||||
|
||||
NSMenuItem* menuItem;
|
||||
menuItem = find_menu_item(menu, menuId);
|
||||
if (menuItem == NULL) {
|
||||
return;
|
||||
}
|
||||
menuItem.image = image;
|
||||
}
|
||||
|
||||
- (void) show_menu_item:(NSNumber*) menuId
|
||||
{
|
||||
NSMenuItem* menuItem = find_menu_item(menu, menuId);
|
||||
if (menuItem != NULL) {
|
||||
[menuItem setHidden:FALSE];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) quit
|
||||
{
|
||||
[NSApp stop:self];
|
||||
[NSApp abortModal];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
void registerSystray(void) {
|
||||
AppDelegate *delegate = [[AppDelegate alloc] init];
|
||||
[[NSApplication sharedApplication] setDelegate:delegate];
|
||||
// A workaround to avoid crashing on macOS versions before Catalina. Somehow
|
||||
// SIGSEGV would happen inside AppKit if [NSApp run] is called from a
|
||||
// different function, even if that function is called right after this.
|
||||
if (floor(NSAppKitVersionNumber) <= /*NSAppKitVersionNumber10_14*/ 1671){
|
||||
[NSApp run];
|
||||
}
|
||||
}
|
||||
|
||||
int nativeLoop(void) {
|
||||
if (floor(NSAppKitVersionNumber) > /*NSAppKitVersionNumber10_14*/ 1671){
|
||||
[NSApp run];
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void runInMainThread(SEL method, id object) {
|
||||
[(AppDelegate*)[NSApp delegate]
|
||||
performSelectorOnMainThread:method
|
||||
withObject:object
|
||||
waitUntilDone: YES];
|
||||
}
|
||||
|
||||
void setIcon(const char* iconBytes, int length, bool template) {
|
||||
NSData* buffer = [NSData dataWithBytes: iconBytes length:length];
|
||||
NSImage *image = [[NSImage alloc] initWithData:buffer];
|
||||
[image setSize:NSMakeSize(16, 16)];
|
||||
image.template = template;
|
||||
runInMainThread(@selector(setIcon:), (id)image);
|
||||
}
|
||||
|
||||
void setMenuItemIcon(const char* iconBytes, int length, int menuId, bool template) {
|
||||
NSData* buffer = [NSData dataWithBytes: iconBytes length:length];
|
||||
NSImage *image = [[NSImage alloc] initWithData:buffer];
|
||||
[image setSize:NSMakeSize(16, 16)];
|
||||
image.template = template;
|
||||
NSNumber *mId = [NSNumber numberWithInt:menuId];
|
||||
runInMainThread(@selector(setMenuItemIcon:), @[image, (id)mId]);
|
||||
}
|
||||
|
||||
void setTitle(char* ctitle) {
|
||||
NSString* title = [[NSString alloc] initWithCString:ctitle
|
||||
encoding:NSUTF8StringEncoding];
|
||||
free(ctitle);
|
||||
runInMainThread(@selector(setTitle:), (id)title);
|
||||
}
|
||||
|
||||
void setTooltip(char* ctooltip) {
|
||||
NSString* tooltip = [[NSString alloc] initWithCString:ctooltip
|
||||
encoding:NSUTF8StringEncoding];
|
||||
free(ctooltip);
|
||||
runInMainThread(@selector(setTooltip:), (id)tooltip);
|
||||
}
|
||||
|
||||
void add_or_update_menu_item(int menuId, int parentMenuId, char* title, char* tooltip, short disabled, short checked, short isCheckable) {
|
||||
MenuItem* item = [[MenuItem alloc] initWithId: menuId withParentMenuId: parentMenuId withTitle: title withTooltip: tooltip withDisabled: disabled withChecked: checked];
|
||||
free(title);
|
||||
free(tooltip);
|
||||
runInMainThread(@selector(add_or_update_menu_item:), (id)item);
|
||||
}
|
||||
|
||||
void add_separator(int menuId) {
|
||||
NSNumber *mId = [NSNumber numberWithInt:menuId];
|
||||
runInMainThread(@selector(add_separator:), (id)mId);
|
||||
}
|
||||
|
||||
void hide_menu_item(int menuId) {
|
||||
NSNumber *mId = [NSNumber numberWithInt:menuId];
|
||||
runInMainThread(@selector(hide_menu_item:), (id)mId);
|
||||
}
|
||||
|
||||
void show_menu_item(int menuId) {
|
||||
NSNumber *mId = [NSNumber numberWithInt:menuId];
|
||||
runInMainThread(@selector(show_menu_item:), (id)mId);
|
||||
}
|
||||
|
||||
void quit() {
|
||||
runInMainThread(@selector(quit), nil);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user