Compare commits
	
		
			23 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					77d6a22122 | ||
| 
						 | 
					40f97073e8 | ||
| 
						 | 
					75339ffba1 | ||
| 
						 | 
					2fdfba5a42 | ||
| 
						 | 
					5987330cdc | ||
| 
						 | 
					14c7c21f9f | ||
| 
						 | 
					fc9fdaf8b6 | ||
| 
						 | 
					5979a6d0e5 | ||
| 
						 | 
					ca2c46ffce | ||
| 
						 | 
					1cc7e92466 | ||
| 
						 | 
					cfc3e81820 | ||
| 
						 | 
					67ab2ab170 | ||
| 
						 | 
					e1ce378421 | ||
| 
						 | 
					f083ea028d | ||
| 
						 | 
					063a82198c | ||
| 
						 | 
					d03c3440de | ||
| 
						 | 
					f7b28ad1e0 | ||
| 
						 | 
					52a95757ce | ||
| 
						 | 
					efc725dadc | ||
| 
						 | 
					ff8c539829 | ||
| 
						 | 
					875e17717e | ||
| 
						 | 
					929f8c19f8 | ||
| 
						 | 
					bdcc856071 | 
@@ -4,19 +4,13 @@ root = true
 | 
			
		||||
charset = utf-8
 | 
			
		||||
end_of_line = lf
 | 
			
		||||
indent_style = space
 | 
			
		||||
indent_size = 4
 | 
			
		||||
indent_size = 2
 | 
			
		||||
insert_final_newline = true
 | 
			
		||||
trim_trailing_whitespace = true
 | 
			
		||||
max_line_length = 120
 | 
			
		||||
 | 
			
		||||
[*.sh]
 | 
			
		||||
indent_size = 2
 | 
			
		||||
 | 
			
		||||
[*.js]
 | 
			
		||||
indent_size = 2
 | 
			
		||||
 | 
			
		||||
[*.vue]
 | 
			
		||||
indent_size = 2
 | 
			
		||||
[*.go]
 | 
			
		||||
indent_size = 4
 | 
			
		||||
 | 
			
		||||
[Makefile]
 | 
			
		||||
indent_style = tab
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
before:
 | 
			
		||||
  hooks:
 | 
			
		||||
    - npm run clean
 | 
			
		||||
    - npm run build
 | 
			
		||||
    - packr
 | 
			
		||||
builds:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								README.md
									
									
									
									
									
								
							@@ -4,13 +4,13 @@ Dozzle is a log viewer for Docker. It's free. It's small. And it's right in your
 | 
			
		||||
 | 
			
		||||
While dozzle should work for most, it is not meant to be a full logging solution. For enterprise use, I recommend you look at [Loggly](https://www.loggly.com), [Papertrail](https://papertrailapp.com) or [Kibana](https://www.elastic.co/products/kibana).
 | 
			
		||||
 | 
			
		||||
But if you don't want to pay for those service, then you are in luck! Dozzle will be able capture all logs from your containers and send them in real-time to your browser. Installation is also very easy.
 | 
			
		||||
But if you don't want to pay for those services, then you are in luck! Dozzle will be able to capture all logs from your containers and send them in real-time to your browser. Installation is also very easy.
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
## Getting dozzle
 | 
			
		||||
 | 
			
		||||
Dozzle is a very small Docker container (13.3MB virtual). Pull the latest release from the index:
 | 
			
		||||
Dozzle is a very small Docker container (4 MB compressed). Pull the latest release from the index:
 | 
			
		||||
 | 
			
		||||
    $ docker pull amir20/dozzle:latest
 | 
			
		||||
 | 
			
		||||
@@ -24,11 +24,21 @@ dozzle will be available at [http://localhost:8888/](http://localhost:8888/). Yo
 | 
			
		||||
 | 
			
		||||
#### Security
 | 
			
		||||
 | 
			
		||||
dozzle doesn't support authentication out of the box. You can control the device dozzle binds to by passing `-addr` parameter. For example,
 | 
			
		||||
dozzle doesn't support authentication out of the box. You can control the device dozzle binds to by passing `--addr` parameter. For example,
 | 
			
		||||
 | 
			
		||||
    $ docker run --volume=/var/run/docker.sock:/var/run/docker.sock -p 8888:1224 amir20/dozzle:latest -addr localhost:1224
 | 
			
		||||
    $ docker run --volume=/var/run/docker.sock:/var/run/docker.sock -p 8888:1224 amir20/dozzle:latest --addr localhost:1224
 | 
			
		||||
 | 
			
		||||
will bind to `localhost` on port `1224`. You can then use a reverse proxy to control who can see dozzle.
 | 
			
		||||
 | 
			
		||||
#### Changing base URL
 | 
			
		||||
 | 
			
		||||
dozzle by default mounts to "/". If you want to control the base path you can use the `--base` option. For example, if you want to mount at "/foobar",
 | 
			
		||||
then you can override by using `--base /foobar`.
 | 
			
		||||
 | 
			
		||||
    $ docker run --volume=/var/run/docker.sock:/var/run/docker.sock -p 8888:8080 amir20/dozzle:latest --base /foobar
 | 
			
		||||
 | 
			
		||||
dozzle will be available at [http://localhost:8080/foobar/](http://localhost:8080/foobar/).
 | 
			
		||||
 | 
			
		||||
will bind to `localhost` on port `1224`. You can then use use reverse proxy to control who can see dozzle.
 | 
			
		||||
 | 
			
		||||
#### Environment variable, DOCKER_API_VERSION
 | 
			
		||||
 | 
			
		||||
@@ -36,7 +46,7 @@ If you see
 | 
			
		||||
 | 
			
		||||
    2018/10/31 08:53:17 Error response from daemon: client version 1.40 is too new. Maximum supported API version is 1.38
 | 
			
		||||
 | 
			
		||||
Then you need to modify `DOCKER_API_VERSION` to let dozzle know which version of the API is supported. By default, `DOCKER_API_VERSION=1.38` and you can change it to by passing `-e` flag. For example, this would change the `DOCKER_API_VERSION` to `1.20`
 | 
			
		||||
Then you need to modify `DOCKER_API_VERSION` to let dozzle know which version of the API is supported. By default, `DOCKER_API_VERSION=1.38` and you can change it by passing `-e` flag. For example, this would change the `DOCKER_API_VERSION` to `1.20`
 | 
			
		||||
 | 
			
		||||
    $ docker run --volume=/var/run/docker.sock:/var/run/docker.sock -e DOCKER_API_VERSION=1.20 -p 8888:8080 amir20/dozzle:latest
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,17 @@
 | 
			
		||||
<template lang="html">
 | 
			
		||||
  <div class="columns is-marginless">
 | 
			
		||||
    <aside class="column menu is-2 section">
 | 
			
		||||
      <h1 class="title has-text-warning">Dozzle</h1>
 | 
			
		||||
      <p class="menu-label">Containers</p>
 | 
			
		||||
      <ul class="menu-list">
 | 
			
		||||
    <aside class="column menu is-2">
 | 
			
		||||
      <a
 | 
			
		||||
        role="button"
 | 
			
		||||
        class="navbar-burger burger is-white is-hidden-tablet is-pulled-right"
 | 
			
		||||
        @click="showNav = !showNav;"
 | 
			
		||||
        :class="{ 'is-active': showNav }"
 | 
			
		||||
      >
 | 
			
		||||
        <span></span> <span></span> <span></span>
 | 
			
		||||
      </a>
 | 
			
		||||
      <h1 class="title has-text-warning is-marginless">Dozzle</h1>
 | 
			
		||||
      <p class="menu-label is-hidden-mobile" :class="{ 'is-active': showNav }">Containers</p>
 | 
			
		||||
      <ul class="menu-list is-hidden-mobile" :class="{ 'is-active': showNav }">
 | 
			
		||||
        <li v-for="item in containers">
 | 
			
		||||
          <router-link
 | 
			
		||||
            :to="{ name: 'container', params: { id: item.Id } }"
 | 
			
		||||
@@ -25,19 +33,48 @@ export default {
 | 
			
		||||
  name: "App",
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      containers: []
 | 
			
		||||
      containers: [],
 | 
			
		||||
      showNav: false
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  async created() {
 | 
			
		||||
    this.containers = await (await fetch(`/api/containers.json`)).json();
 | 
			
		||||
    this.containers = await (await fetch(`${BASE_PATH}/api/containers.json`)).json();
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.is-hidden-mobile.is-active {
 | 
			
		||||
  display: block !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navbar-burger {
 | 
			
		||||
  height: 2.35rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
aside {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  padding-right: 0;
 | 
			
		||||
  z-index: 2;
 | 
			
		||||
  padding: 1em;
 | 
			
		||||
 | 
			
		||||
  @media screen and (max-width: 768px) {
 | 
			
		||||
    & {
 | 
			
		||||
      position: sticky;
 | 
			
		||||
      top: 0;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      right: 0;
 | 
			
		||||
      background: #222;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .tooltip::after,
 | 
			
		||||
    .tooltip::before {
 | 
			
		||||
      display: none !important;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .menu-label {
 | 
			
		||||
      margin-top: 1em;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hide-overflow {
 | 
			
		||||
@@ -45,4 +82,8 @@ aside {
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.burger.is-white {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +1,20 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
        <meta charset="utf-8" />
 | 
			
		||||
        <meta name="viewport" content="width=device-width, initial-scale=1" />
 | 
			
		||||
        <title>Dozzle</title>
 | 
			
		||||
        <link href="https://fonts.googleapis.com/css?family=Roboto|Roboto+Mono|Gafata" rel="stylesheet">
 | 
			
		||||
        <link href="./styles.scss" rel="stylesheet">
 | 
			
		||||
        <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
 | 
			
		||||
    </head>
 | 
			
		||||
  <head>
 | 
			
		||||
    <meta charset="utf-8" />
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1" />
 | 
			
		||||
    <title>{{ .Hostname }} - Dozzle</title>
 | 
			
		||||
    <link href="https://fonts.googleapis.com/css?family=Roboto|Roboto+Mono|Gafata" rel="stylesheet" />
 | 
			
		||||
    <link href="styles.scss" rel="stylesheet" />
 | 
			
		||||
    <script>
 | 
			
		||||
      window["BASE_PATH"] = "{{ .Base }}";
 | 
			
		||||
      window["SSL_ENABLED"] = "{{ .SSL }}".toLowerCase() === "true";
 | 
			
		||||
    </script>
 | 
			
		||||
    <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
 | 
			
		||||
  </head>
 | 
			
		||||
 | 
			
		||||
    <body class="is-dark">
 | 
			
		||||
        <div id="app"></div>
 | 
			
		||||
        <script src="/main.js"></script>
 | 
			
		||||
    </body>
 | 
			
		||||
  <body class="is-dark">
 | 
			
		||||
    <div id="app"></div>
 | 
			
		||||
    <script src="main.js"></script>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@ const routes = [
 | 
			
		||||
 | 
			
		||||
const router = new VueRouter({
 | 
			
		||||
  mode: "history",
 | 
			
		||||
  base: BASE_PATH + "/",
 | 
			
		||||
  routes
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,8 @@ export default {
 | 
			
		||||
        ws = null;
 | 
			
		||||
        this.messages = [];
 | 
			
		||||
      }
 | 
			
		||||
      ws = new WebSocket(`ws://${window.location.host}/api/logs?id=${this.id}`);
 | 
			
		||||
      const protocol = SSL_ENABLED ? "wss" : "ws";
 | 
			
		||||
      ws = new WebSocket(`${protocol}://${window.location.host}${BASE_PATH}/api/logs?id=${this.id}`);
 | 
			
		||||
      ws.onopen = e => console.log("Connection opened.");
 | 
			
		||||
      ws.onclose = e => console.log("Connection closed.");
 | 
			
		||||
      ws.onerror = e => console.error("Connection error: " + e.data);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								demo.gif
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								demo.gif
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 41 MiB After Width: | Height: | Size: 24 MiB  | 
							
								
								
									
										195
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										195
									
								
								main.go
									
									
									
									
									
								
							@@ -1,103 +1,146 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
    "context"
 | 
			
		||||
    "encoding/binary"
 | 
			
		||||
    "encoding/json"
 | 
			
		||||
    "fmt"
 | 
			
		||||
    "html/template"
 | 
			
		||||
    "log"
 | 
			
		||||
    "net/http"
 | 
			
		||||
    "os"
 | 
			
		||||
    "strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/docker/api/types"
 | 
			
		||||
	"github.com/docker/docker/client"
 | 
			
		||||
	"github.com/gobuffalo/packr"
 | 
			
		||||
	"github.com/gorilla/websocket"
 | 
			
		||||
    "github.com/docker/docker/api/types"
 | 
			
		||||
    "github.com/docker/docker/client"
 | 
			
		||||
    "github.com/gobuffalo/packr"
 | 
			
		||||
    "github.com/gorilla/mux"
 | 
			
		||||
    "github.com/gorilla/websocket"
 | 
			
		||||
    flag "github.com/spf13/pflag"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	cli      *client.Client
 | 
			
		||||
	addr     = flag.String("addr", ":8080", "http service address")
 | 
			
		||||
	upgrader = websocket.Upgrader{}
 | 
			
		||||
	version  = "dev"
 | 
			
		||||
	commit   = "none"
 | 
			
		||||
	date     = "unknown"
 | 
			
		||||
    cli      *client.Client
 | 
			
		||||
    addr     = ""
 | 
			
		||||
    ssl      = false
 | 
			
		||||
    base     = "/"
 | 
			
		||||
    upgrader = websocket.Upgrader{}
 | 
			
		||||
    version  = "dev"
 | 
			
		||||
    commit   = "none"
 | 
			
		||||
    date     = "unknown"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	var err error
 | 
			
		||||
	cli, err = client.NewClientWithOpts(client.FromEnv)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
    flag.StringVar(&addr, "addr", ":8080", "http service address")
 | 
			
		||||
    flag.StringVar(&base, "base", "/", "base address of the application to mount")
 | 
			
		||||
    flag.BoolVarP(&ssl, "ssl", "s", false, "Uses websockets over ssl if enabled")
 | 
			
		||||
 | 
			
		||||
    var err error
 | 
			
		||||
    cli, err = client.NewClientWithOpts(client.FromEnv)
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        log.Fatal(err)
 | 
			
		||||
    }
 | 
			
		||||
    flag.Parse()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	box := packr.NewBox("./static")
 | 
			
		||||
	http.HandleFunc("/api/containers.json", listContainers)
 | 
			
		||||
	http.HandleFunc("/api/logs", logs)
 | 
			
		||||
	http.HandleFunc("/version", versionHandler)
 | 
			
		||||
	http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
			
		||||
		fileServer := http.FileServer(box)
 | 
			
		||||
		if box.Has(req.URL.Path) {
 | 
			
		||||
			fileServer.ServeHTTP(w, req)
 | 
			
		||||
		} else {
 | 
			
		||||
			bytes, _ := box.Find("index.html")
 | 
			
		||||
			w.Write(bytes)
 | 
			
		||||
		}
 | 
			
		||||
	}))
 | 
			
		||||
    r := mux.NewRouter()
 | 
			
		||||
 | 
			
		||||
	log.Fatal(http.ListenAndServe(*addr, nil))
 | 
			
		||||
    if base != "/" {
 | 
			
		||||
        r.HandleFunc(base, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
			
		||||
            http.Redirect(w, req, base+"/", http.StatusMovedPermanently)
 | 
			
		||||
        }))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    s := r.PathPrefix(base).Subrouter()
 | 
			
		||||
    box := packr.NewBox("./static")
 | 
			
		||||
 | 
			
		||||
    s.HandleFunc("/api/containers.json", listContainers)
 | 
			
		||||
    s.HandleFunc("/api/logs", logs)
 | 
			
		||||
    s.HandleFunc("/version", versionHandler)
 | 
			
		||||
    s.PathPrefix("/").Handler(http.StripPrefix(base, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 | 
			
		||||
        fileServer := http.FileServer(box)
 | 
			
		||||
        if box.Has(req.URL.Path) && req.URL.Path != "" && req.URL.Path != "/" {
 | 
			
		||||
            fileServer.ServeHTTP(w, req)
 | 
			
		||||
        } else {
 | 
			
		||||
            handleIndex(box, w)
 | 
			
		||||
        }
 | 
			
		||||
    })))
 | 
			
		||||
 | 
			
		||||
    log.Fatal(http.ListenAndServe(addr, r))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func versionHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	fmt.Fprintln(w, version)
 | 
			
		||||
	fmt.Fprintln(w, commit)
 | 
			
		||||
	fmt.Fprintln(w, date)
 | 
			
		||||
    fmt.Fprintln(w, version)
 | 
			
		||||
    fmt.Fprintln(w, commit)
 | 
			
		||||
    fmt.Fprintln(w, date)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func listContainers(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	json.NewEncoder(w).Encode(containers)
 | 
			
		||||
    containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        log.Fatal(err)
 | 
			
		||||
    }
 | 
			
		||||
    json.NewEncoder(w).Encode(containers)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handleIndex(box packr.Box, w http.ResponseWriter) {
 | 
			
		||||
    text, _ := box.FindString("index.html")
 | 
			
		||||
    text = strings.Replace(text, "__BASE__", "{{ .Base }}", -1)
 | 
			
		||||
    tmpl, err := template.New("index.html").Parse(text)
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        panic(err)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    path := ""
 | 
			
		||||
    if base != "/" {
 | 
			
		||||
        path = base
 | 
			
		||||
    }
 | 
			
		||||
    hostname, _ := os.Hostname()
 | 
			
		||||
    data := struct {
 | 
			
		||||
        Base     string
 | 
			
		||||
        SSL      bool
 | 
			
		||||
        Hostname string
 | 
			
		||||
    }{path, ssl, hostname}
 | 
			
		||||
    err = tmpl.Execute(w, data)
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        panic(err)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func logs(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	id := r.URL.Query().Get("id")
 | 
			
		||||
	c, err := upgrader.Upgrade(w, r, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer c.Close()
 | 
			
		||||
    id := r.URL.Query().Get("id")
 | 
			
		||||
    c, err := upgrader.Upgrade(w, r, nil)
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        log.Fatal(err)
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
    defer c.Close()
 | 
			
		||||
 | 
			
		||||
	options := types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: true, Tail: "300", Timestamps: true}
 | 
			
		||||
	reader, err := cli.ContainerLogs(context.Background(), id, options)
 | 
			
		||||
	defer reader.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
    options := types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Follow: true, Tail: "300", Timestamps: true}
 | 
			
		||||
    reader, err := cli.ContainerLogs(context.Background(), id, options)
 | 
			
		||||
    defer reader.Close()
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        log.Fatal(err)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	hdr := make([]byte, 8)
 | 
			
		||||
	content := make([]byte, 1024, 1024*1024)
 | 
			
		||||
	for {
 | 
			
		||||
		_, err := reader.Read(hdr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
    hdr := make([]byte, 8)
 | 
			
		||||
    content := make([]byte, 1024, 1024*1024)
 | 
			
		||||
    for {
 | 
			
		||||
        _, err := reader.Read(hdr)
 | 
			
		||||
        if err != nil {
 | 
			
		||||
            log.Panicln(err)
 | 
			
		||||
		}
 | 
			
		||||
		count := binary.BigEndian.Uint32(hdr[4:])
 | 
			
		||||
		n, err := reader.Read(content[:count])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		err = c.WriteMessage(websocket.TextMessage, content[:n])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Println(err)
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
        }
 | 
			
		||||
        count := binary.BigEndian.Uint32(hdr[4:])
 | 
			
		||||
        n, err := reader.Read(content[:count])
 | 
			
		||||
        if err != nil {
 | 
			
		||||
            log.Println(err)
 | 
			
		||||
            break
 | 
			
		||||
        }
 | 
			
		||||
        err = c.WriteMessage(websocket.TextMessage, content[:n])
 | 
			
		||||
        if err != nil {
 | 
			
		||||
            log.Println(err)
 | 
			
		||||
            break
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										22
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "dozzle",
 | 
			
		||||
  "version": "1.0.16",
 | 
			
		||||
  "version": "1.2.5",
 | 
			
		||||
  "lockfileVersion": 1,
 | 
			
		||||
  "requires": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
@@ -4648,9 +4648,9 @@
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "husky": {
 | 
			
		||||
      "version": "1.1.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/husky/-/husky-1.1.4.tgz",
 | 
			
		||||
      "integrity": "sha512-cZjGpS7qsaBSo3fOMUuR7erQloX3l5XzL1v/RkIqU6zrQImDdU70z5Re9fGDp7+kbYlM2EtS4aYMlahBeiCUGw==",
 | 
			
		||||
      "version": "1.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/husky/-/husky-1.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-/ib3+iycykXC0tYIxsyqierikVa9DA2DrT32UEirqNEFVqOj1bFMTgP3jAz8HM7FgC/C8pc/BTUa9MV2GEkZaA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "cosmiconfig": "^5.0.6",
 | 
			
		||||
@@ -5195,15 +5195,15 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "lint-staged": {
 | 
			
		||||
      "version": "8.0.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.0.5.tgz",
 | 
			
		||||
      "integrity": "sha512-QI2D6lw2teArlr2fmrrCIqHxef7mK2lKjz9e+aZSzFlk5rsy10rg97p3wA9H/vIFR3Fvn34fAgUktD/k896S2A==",
 | 
			
		||||
      "version": "8.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.0.tgz",
 | 
			
		||||
      "integrity": "sha512-yfSkyJy7EuVsaoxtUSEhrD81spdJOe/gMTGea3XaV7HyoRhTb9Gdlp6/JppRZERvKSEYXP9bjcmq6CA5oL2lYQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "@iamstarkov/listr-update-renderer": "0.4.1",
 | 
			
		||||
        "chalk": "^2.3.1",
 | 
			
		||||
        "commander": "^2.14.1",
 | 
			
		||||
        "cosmiconfig": "^5.0.2",
 | 
			
		||||
        "cosmiconfig": "5.0.6",
 | 
			
		||||
        "debug": "^3.1.0",
 | 
			
		||||
        "dedent": "^0.7.0",
 | 
			
		||||
        "del": "^3.0.0",
 | 
			
		||||
@@ -9133,9 +9133,9 @@
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "vue-router": {
 | 
			
		||||
      "version": "3.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-vLLoY452L+JBpALMP5UHum9+7nzR9PeIBCghU9ZtJ1eWm6ieUI8Zb/DI3MYxH32bxkjzYV1LRjNv4qr8d+uX/w=="
 | 
			
		||||
      "version": "3.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-opKtsxjp9eOcFWdp6xLQPLmRGgfM932Tl56U9chYTnoWqKxQ8M20N7AkdEbM5beUh6wICoFGYugAX9vQjyJLFg=="
 | 
			
		||||
    },
 | 
			
		||||
    "vue-template-compiler": {
 | 
			
		||||
      "version": "2.5.17",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								package.json
									
									
									
									
									
								
							@@ -1,13 +1,15 @@
 | 
			
		||||
{
 | 
			
		||||
 "name": "dozzle",
 | 
			
		||||
 "version": "1.0.16",
 | 
			
		||||
 "version": "1.2.5",
 | 
			
		||||
 "description": "",
 | 
			
		||||
 "main": "index.js",
 | 
			
		||||
 "scripts": {
 | 
			
		||||
  "start": "concurrently 'go run main.go' 'npm run watch-assets'",
 | 
			
		||||
  "watch-assets": "parcel watch assets/index.html -d static",
 | 
			
		||||
  "build": "parcel build assets/index.html -d static",
 | 
			
		||||
  "clean": "rm -rf static"
 | 
			
		||||
  "watch-assets": "parcel watch --public-url '__BASE__' assets/index.html -d static",
 | 
			
		||||
  "prebuild": "npm run clean",
 | 
			
		||||
  "build": "parcel build --no-source-maps --public-url '__BASE__' assets/index.html -d static",
 | 
			
		||||
  "clean": "rm -rf static",
 | 
			
		||||
  "release": "goreleaser --rm-dist"
 | 
			
		||||
 },
 | 
			
		||||
 "repository": {
 | 
			
		||||
  "type": "git",
 | 
			
		||||
@@ -24,15 +26,15 @@
 | 
			
		||||
  "bulma-tooltip": "^2.0.2",
 | 
			
		||||
  "date-fns": "^2.0.0-alpha.25",
 | 
			
		||||
  "vue": "^2.5.17",
 | 
			
		||||
  "vue-router": "^3.0.1"
 | 
			
		||||
  "vue-router": "^3.0.2"
 | 
			
		||||
 },
 | 
			
		||||
 "devDependencies": {
 | 
			
		||||
  "@babel/core": "^7.1.6",
 | 
			
		||||
  "@babel/plugin-transform-runtime": "^7.1.0",
 | 
			
		||||
  "@vue/component-compiler-utils": "^2.3.0",
 | 
			
		||||
  "concurrently": "^4.1.0",
 | 
			
		||||
  "husky": "^1.1.4",
 | 
			
		||||
  "lint-staged": "^8.0.5",
 | 
			
		||||
  "husky": "^1.2.0",
 | 
			
		||||
  "lint-staged": "^8.1.0",
 | 
			
		||||
  "parcel-bundler": "^1.10.3",
 | 
			
		||||
  "prettier": "^1.15.2",
 | 
			
		||||
  "sass": "^1.15.1",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user