Create & Init Project...
This commit is contained in:
commit
0c567a6c8a
28
.gitignore
vendored
Normal file
28
.gitignore
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
# ---> Go
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
/vendor
|
||||
main
|
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@ -0,0 +1,17 @@
|
||||
FROM golang:alpine AS build
|
||||
|
||||
WORKDIR /go/src/github.com/yumc.pw/cloud/html2pic
|
||||
ADD . .
|
||||
RUN go build -o main
|
||||
|
||||
FROM alpine:edge
|
||||
LABEL maintainer="MiaoWoo<admin@yumc.pw>"
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
WORKDIR /root
|
||||
RUN apk add --no-cache ca-certificates
|
||||
|
||||
COPY --from=build /go/src/github.com/yumc.pw/cloud/html2pic/main ./main
|
||||
ADD lib /root/lib
|
||||
|
||||
CMD ./main -lib /root/lib
|
BIN
lib/phantomjs
Executable file
BIN
lib/phantomjs
Executable file
Binary file not shown.
138
lib/screenshot.js
Normal file
138
lib/screenshot.js
Normal file
@ -0,0 +1,138 @@
|
||||
var page = require('webpage').create(),
|
||||
system = require('system'),
|
||||
isDev = false,
|
||||
reRunNum = 2,
|
||||
resourceError = null;
|
||||
if (system.args.length < 3) {
|
||||
phantom.exit(1);
|
||||
}
|
||||
if (system.args[3]) {
|
||||
isDev = true;
|
||||
}
|
||||
if (isDev) {
|
||||
console.log(navigator.userAgent);
|
||||
var s = (new Date()).getTime();
|
||||
page.onConsoleMessage = function (msg) {
|
||||
console.log(msg);
|
||||
};
|
||||
page.onError = function (msg, trace) {
|
||||
console.log(msg + ';;errInfo' + JSON.stringify(trace));
|
||||
}
|
||||
} else {
|
||||
console.log = function () {
|
||||
};
|
||||
}
|
||||
|
||||
page.onResourceError = function (error) {
|
||||
if (error.url == system.args[1]) {
|
||||
console.log('pageLoadError:' + JSON.stringify(error));
|
||||
resourceError = error;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
_run();
|
||||
setTimeout(function () {
|
||||
console.log('pageTimeOut');
|
||||
phantom.exit(2);
|
||||
}, 20000)
|
||||
|
||||
function _run() {
|
||||
page.open(system.args[1], function (status) {
|
||||
if (status == 'fail') {
|
||||
if (!_reRun()) {
|
||||
phantom.exit(2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var staticWaitNum = 10, pageWaitNum = 15, cd = 200, over, resources = {}, start = false, initRender = false;
|
||||
|
||||
page.onResourceRequested = function (request) {
|
||||
if (!start) {
|
||||
start = true;
|
||||
}
|
||||
resources[request.id + ''] = 0;
|
||||
console.log('request -' + request.id + ':' + request.url);
|
||||
}
|
||||
|
||||
page.onResourceReceived = function (response) {
|
||||
if (!start) {
|
||||
start = true;
|
||||
}
|
||||
if (response.stage == "end") {
|
||||
delete resources[response.id + ''];
|
||||
console.log('response-' + response.id + ':' + response.url);
|
||||
}
|
||||
}
|
||||
|
||||
function initOver() {
|
||||
clearTimeout(over);
|
||||
over = setTimeout(function () {
|
||||
console.log('time:' + ((new Date()).getTime() - s) + '---resources' + JSON.stringify(resources));
|
||||
if (resourceError != null && resourceError.status != 200) {
|
||||
phantom.exit(3);
|
||||
}
|
||||
if (!initRender) {
|
||||
console.log('initRender');
|
||||
initRender = true;
|
||||
page.render(system.args[2]);
|
||||
}
|
||||
|
||||
if (!start) {
|
||||
if (pageWaitNum-- > 0) {
|
||||
console.log('pageWaitNum:' + pageWaitNum);
|
||||
initOver();
|
||||
return;
|
||||
} else {
|
||||
if (!_reRun()) {
|
||||
_render();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
var keys = _keys(resources), k;
|
||||
for (var i in keys) {
|
||||
k = keys[i];
|
||||
resources[k]++;
|
||||
if (resources[k] > staticWaitNum) {
|
||||
console.log('timeOver:' + k);
|
||||
delete resources[k];
|
||||
}
|
||||
}
|
||||
if (_keys(resources).length > 0) {
|
||||
initOver();
|
||||
return;
|
||||
}
|
||||
_render();
|
||||
}, cd);
|
||||
}
|
||||
|
||||
initOver();
|
||||
});
|
||||
}
|
||||
|
||||
function _render() {
|
||||
page.render(system.args[2]);
|
||||
console.log('overTime:' + ((new Date()).getTime() - s));
|
||||
phantom.exit(0);
|
||||
}
|
||||
|
||||
function _reRun() {
|
||||
if (reRunNum-- > 0) {
|
||||
console.log('reRun');
|
||||
_run();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function _keys(m) {
|
||||
var ks = [];
|
||||
for (var k in m) {
|
||||
if (m.hasOwnProperty(k)) {
|
||||
ks.push(k);
|
||||
}
|
||||
}
|
||||
return ks;
|
||||
}
|
43
main.go
Normal file
43
main.go
Normal file
@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"yumc.pw/cloud/html2pic/uuid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b := flag.String("b", ":8080", "Server Bind Address")
|
||||
lib := flag.String("lib", "/root", "Set Phantomjs Root Path")
|
||||
tempDir := flag.String("temp", os.TempDir(), "")
|
||||
flag.Parse()
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
uid, _ := uuid.NewV4()
|
||||
uuid := "html2pic-" + uid.String()
|
||||
url, html := r.FormValue("url"), r.FormValue("html")
|
||||
tempFile := *tempDir + "/" + uuid + ".html"
|
||||
if html != "" {
|
||||
ioutil.WriteFile(tempFile, []byte("<!DOCTYPE html><html lang=\"zh\"><head><meta charset=\"UTF-8\"></head><body style=\"margin: 0;padding: 0;\">"+html+"</body></html>"), os.ModeAppend)
|
||||
url = "file://" + tempFile
|
||||
defer os.Remove(tempFile)
|
||||
}
|
||||
if url == "" {
|
||||
w.Write([]byte("Empty Url..."))
|
||||
return
|
||||
}
|
||||
tempPic := *tempDir + "/" + uuid + ".png"
|
||||
err := exec.Command(*lib+"/phantomjs", *lib+"/screenshot.js", url, tempPic).Run()
|
||||
defer os.Remove(tempPic)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
bytes, _ := ioutil.ReadFile(tempPic)
|
||||
w.Write(bytes)
|
||||
})
|
||||
http.ListenAndServe(*b, nil)
|
||||
}
|
244
uuid/g.go
Normal file
244
uuid/g.go
Normal file
@ -0,0 +1,244 @@
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Difference in 100-nanosecond intervals between
|
||||
// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
|
||||
const epochStart = 122192928000000000
|
||||
|
||||
type epochFunc func() time.Time
|
||||
type hwAddrFunc func() (net.HardwareAddr, error)
|
||||
|
||||
var (
|
||||
global = newRFC4122Generator()
|
||||
|
||||
posixUID = uint32(os.Getuid())
|
||||
posixGID = uint32(os.Getgid())
|
||||
)
|
||||
|
||||
// NewV1 returns UUID based on current timestamp and MAC address.
|
||||
func NewV1() (UUID, error) {
|
||||
return global.NewV1()
|
||||
}
|
||||
|
||||
// NewV2 returns DCE Security UUID based on POSIX UID/GID.
|
||||
func NewV2(domain byte) (UUID, error) {
|
||||
return global.NewV2(domain)
|
||||
}
|
||||
|
||||
// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
|
||||
func NewV3(ns UUID, name string) UUID {
|
||||
return global.NewV3(ns, name)
|
||||
}
|
||||
|
||||
// NewV4 returns random generated UUID.
|
||||
func NewV4() (UUID, error) {
|
||||
return global.NewV4()
|
||||
}
|
||||
|
||||
// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
|
||||
func NewV5(ns UUID, name string) UUID {
|
||||
return global.NewV5(ns, name)
|
||||
}
|
||||
|
||||
// Generator provides interface for generating UUIDs.
|
||||
type Generator interface {
|
||||
NewV1() (UUID, error)
|
||||
NewV2(domain byte) (UUID, error)
|
||||
NewV3(ns UUID, name string) UUID
|
||||
NewV4() (UUID, error)
|
||||
NewV5(ns UUID, name string) UUID
|
||||
}
|
||||
|
||||
// Default generator implementation.
|
||||
type rfc4122Generator struct {
|
||||
clockSequenceOnce sync.Once
|
||||
hardwareAddrOnce sync.Once
|
||||
storageMutex sync.Mutex
|
||||
|
||||
rand io.Reader
|
||||
|
||||
epochFunc epochFunc
|
||||
hwAddrFunc hwAddrFunc
|
||||
lastTime uint64
|
||||
clockSequence uint16
|
||||
hardwareAddr [6]byte
|
||||
}
|
||||
|
||||
func newRFC4122Generator() Generator {
|
||||
return &rfc4122Generator{
|
||||
epochFunc: time.Now,
|
||||
hwAddrFunc: defaultHWAddrFunc,
|
||||
rand: rand.Reader,
|
||||
}
|
||||
}
|
||||
|
||||
// NewV1 returns UUID based on current timestamp and MAC address.
|
||||
func (g *rfc4122Generator) NewV1() (UUID, error) {
|
||||
u := UUID{}
|
||||
|
||||
timeNow, clockSeq, err := g.getClockSequence()
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
|
||||
binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
|
||||
binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
|
||||
binary.BigEndian.PutUint16(u[8:], clockSeq)
|
||||
|
||||
hardwareAddr, err := g.getHardwareAddr()
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
copy(u[10:], hardwareAddr)
|
||||
|
||||
u.SetVersion(V1)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// NewV2 returns DCE Security UUID based on POSIX UID/GID.
|
||||
func (g *rfc4122Generator) NewV2(domain byte) (UUID, error) {
|
||||
u, err := g.NewV1()
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
|
||||
switch domain {
|
||||
case DomainPerson:
|
||||
binary.BigEndian.PutUint32(u[:], posixUID)
|
||||
case DomainGroup:
|
||||
binary.BigEndian.PutUint32(u[:], posixGID)
|
||||
}
|
||||
|
||||
u[9] = domain
|
||||
|
||||
u.SetVersion(V2)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
|
||||
func (g *rfc4122Generator) NewV3(ns UUID, name string) UUID {
|
||||
u := newFromHash(md5.New(), ns, name)
|
||||
u.SetVersion(V3)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
// NewV4 returns random generated UUID.
|
||||
func (g *rfc4122Generator) NewV4() (UUID, error) {
|
||||
u := UUID{}
|
||||
if _, err := g.rand.Read(u[:]); err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
u.SetVersion(V4)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
|
||||
func (g *rfc4122Generator) NewV5(ns UUID, name string) UUID {
|
||||
u := newFromHash(sha1.New(), ns, name)
|
||||
u.SetVersion(V5)
|
||||
u.SetVariant(VariantRFC4122)
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
// Returns epoch and clock sequence.
|
||||
func (g *rfc4122Generator) getClockSequence() (uint64, uint16, error) {
|
||||
var err error
|
||||
g.clockSequenceOnce.Do(func() {
|
||||
buf := make([]byte, 2)
|
||||
if _, err = g.rand.Read(buf); err != nil {
|
||||
return
|
||||
}
|
||||
g.clockSequence = binary.BigEndian.Uint16(buf)
|
||||
})
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
g.storageMutex.Lock()
|
||||
defer g.storageMutex.Unlock()
|
||||
|
||||
timeNow := g.getEpoch()
|
||||
// Clock didn't change since last UUID generation.
|
||||
// Should increase clock sequence.
|
||||
if timeNow <= g.lastTime {
|
||||
g.clockSequence++
|
||||
}
|
||||
g.lastTime = timeNow
|
||||
|
||||
return timeNow, g.clockSequence, nil
|
||||
}
|
||||
|
||||
// Returns hardware address.
|
||||
func (g *rfc4122Generator) getHardwareAddr() ([]byte, error) {
|
||||
var err error
|
||||
g.hardwareAddrOnce.Do(func() {
|
||||
if hwAddr, err := g.hwAddrFunc(); err == nil {
|
||||
copy(g.hardwareAddr[:], hwAddr)
|
||||
return
|
||||
}
|
||||
|
||||
// Initialize hardwareAddr randomly in case
|
||||
// of real network interfaces absence.
|
||||
if _, err = g.rand.Read(g.hardwareAddr[:]); err != nil {
|
||||
return
|
||||
}
|
||||
// Set multicast bit as recommended by RFC 4122
|
||||
g.hardwareAddr[0] |= 0x01
|
||||
})
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return g.hardwareAddr[:], nil
|
||||
}
|
||||
|
||||
// Returns difference in 100-nanosecond intervals between
|
||||
// UUID epoch (October 15, 1582) and current time.
|
||||
func (g *rfc4122Generator) getEpoch() uint64 {
|
||||
return epochStart + uint64(g.epochFunc().UnixNano()/100)
|
||||
}
|
||||
|
||||
// Returns UUID based on hashing of namespace UUID and name.
|
||||
func newFromHash(h hash.Hash, ns UUID, name string) UUID {
|
||||
u := UUID{}
|
||||
h.Write(ns[:])
|
||||
h.Write([]byte(name))
|
||||
copy(u[:], h.Sum(nil))
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
// Returns hardware address.
|
||||
func defaultHWAddrFunc() (net.HardwareAddr, error) {
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
for _, iface := range ifaces {
|
||||
if len(iface.HardwareAddr) >= 6 {
|
||||
return iface.HardwareAddr, nil
|
||||
}
|
||||
}
|
||||
return []byte{}, fmt.Errorf("uuid: no HW address found")
|
||||
}
|
129
uuid/uuid.go
Normal file
129
uuid/uuid.go
Normal file
@ -0,0 +1,129 @@
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
// Size of a UUID in bytes.
|
||||
const Size = 16
|
||||
|
||||
// UUID representation compliant with specification
|
||||
// described in RFC 4122.
|
||||
type UUID [Size]byte
|
||||
|
||||
// UUID versions
|
||||
const (
|
||||
_ byte = iota
|
||||
V1
|
||||
V2
|
||||
V3
|
||||
V4
|
||||
V5
|
||||
)
|
||||
|
||||
// UUID layout variants.
|
||||
const (
|
||||
VariantNCS byte = iota
|
||||
VariantRFC4122
|
||||
VariantMicrosoft
|
||||
VariantFuture
|
||||
)
|
||||
|
||||
// UUID DCE domains.
|
||||
const (
|
||||
DomainPerson = iota
|
||||
DomainGroup
|
||||
DomainOrg
|
||||
)
|
||||
|
||||
// String parse helpers.
|
||||
var (
|
||||
urnPrefix = []byte("urn:uuid:")
|
||||
byteGroups = []int{8, 4, 4, 4, 12}
|
||||
)
|
||||
|
||||
// Nil is special form of UUID that is specified to have all
|
||||
// 128 bits set to zero.
|
||||
var Nil = UUID{}
|
||||
|
||||
// Equal returns true if u1 and u2 equals, otherwise returns false.
|
||||
func Equal(u1 UUID, u2 UUID) bool {
|
||||
return bytes.Equal(u1[:], u2[:])
|
||||
}
|
||||
|
||||
// Version returns algorithm version used to generate UUID.
|
||||
func (u UUID) Version() byte {
|
||||
return u[6] >> 4
|
||||
}
|
||||
|
||||
// Variant returns UUID layout variant.
|
||||
func (u UUID) Variant() byte {
|
||||
switch {
|
||||
case (u[8] >> 7) == 0x00:
|
||||
return VariantNCS
|
||||
case (u[8] >> 6) == 0x02:
|
||||
return VariantRFC4122
|
||||
case (u[8] >> 5) == 0x06:
|
||||
return VariantMicrosoft
|
||||
case (u[8] >> 5) == 0x07:
|
||||
fallthrough
|
||||
default:
|
||||
return VariantFuture
|
||||
}
|
||||
}
|
||||
|
||||
// Bytes returns bytes slice representation of UUID.
|
||||
func (u UUID) Bytes() []byte {
|
||||
return u[:]
|
||||
}
|
||||
|
||||
// Returns canonical string representation of UUID:
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
|
||||
func (u UUID) String() string {
|
||||
buf := make([]byte, 36)
|
||||
|
||||
hex.Encode(buf[0:8], u[0:4])
|
||||
buf[8] = '-'
|
||||
hex.Encode(buf[9:13], u[4:6])
|
||||
buf[13] = '-'
|
||||
hex.Encode(buf[14:18], u[6:8])
|
||||
buf[18] = '-'
|
||||
hex.Encode(buf[19:23], u[8:10])
|
||||
buf[23] = '-'
|
||||
hex.Encode(buf[24:], u[10:])
|
||||
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
// SetVersion sets version bits.
|
||||
func (u *UUID) SetVersion(v byte) {
|
||||
u[6] = (u[6] & 0x0f) | (v << 4)
|
||||
}
|
||||
|
||||
// SetVariant sets variant bits.
|
||||
func (u *UUID) SetVariant(v byte) {
|
||||
switch v {
|
||||
case VariantNCS:
|
||||
u[8] = (u[8]&(0xff>>1) | (0x00 << 7))
|
||||
case VariantRFC4122:
|
||||
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
|
||||
case VariantMicrosoft:
|
||||
u[8] = (u[8]&(0xff>>3) | (0x06 << 5))
|
||||
case VariantFuture:
|
||||
fallthrough
|
||||
default:
|
||||
u[8] = (u[8]&(0xff>>3) | (0x07 << 5))
|
||||
}
|
||||
}
|
||||
|
||||
// Must is a helper that wraps a call to a function returning (UUID, error)
|
||||
// and panics if the error is non-nil. It is intended for use in variable
|
||||
// initializations such as
|
||||
// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"));
|
||||
func Must(u UUID, err error) UUID {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return u
|
||||
}
|
Loading…
Reference in New Issue
Block a user