1
0

Create & Init Project...

This commit is contained in:
502647092 2018-09-11 18:57:48 +08:00
commit 0c567a6c8a
7 changed files with 599 additions and 0 deletions

28
.gitignore vendored Normal file
View 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
View 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

Binary file not shown.

138
lib/screenshot.js Normal file
View 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
View 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
View 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
View 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
}