@ -13,12 +13,13 @@ import (
// to the dnsseeder
// to the dnsseeder
func startHTTP ( port string ) {
func startHTTP ( port string ) {
http . HandleFunc ( "/dns" , dnsHandler )
http . HandleFunc ( "/dns" , dnsWeb Handler )
http . HandleFunc ( "/twistee" , twiste eHandler )
http . HandleFunc ( "/node" , nod eHandler )
http . HandleFunc ( "/statusRG" , statusRGHandler )
http . HandleFunc ( "/statusRG" , statusRGHandler )
http . HandleFunc ( "/statusCG" , statusCGHandler )
http . HandleFunc ( "/statusCG" , statusCGHandler )
http . HandleFunc ( "/statusWG" , statusWGHandler )
http . HandleFunc ( "/statusWG" , statusWGHandler )
http . HandleFunc ( "/statusNG" , statusNGHandler )
http . HandleFunc ( "/statusNG" , statusNGHandler )
http . HandleFunc ( "/summary" , summaryHandler )
http . HandleFunc ( "/" , emptyHandler )
http . HandleFunc ( "/" , emptyHandler )
// listen only on localhost
// listen only on localhost
err := http . ListenAndServe ( "127.0.0.1:" + port , nil )
err := http . ListenAndServe ( "127.0.0.1:" + port , nil )
@ -28,18 +29,30 @@ func startHTTP(port string) {
}
}
// reflect Handler processes all requests and returns output in the requested format
// dnsWeb Handler processes all requests and returns output in the requested format
func dnsHandler ( w http . ResponseWriter , r * http . Request ) {
func dnsWeb Handler ( w http . ResponseWriter , r * http . Request ) {
st := time . Now ( )
st := time . Now ( )
// skip the s= from the raw query
n := r . FormValue ( "s" )
s := getSeederByName ( n )
if s == nil {
writeHeader ( w , r )
fmt . Fprintf ( w , "No seeder found: %s" , html . EscapeString ( n ) )
writeFooter ( w , r , st )
return
}
// FIXME - This is ugly code and needs to be cleaned up a lot
// FIXME - This is ugly code and needs to be cleaned up a lot
// get v4 std addresses
config . dnsmtx . RLock ( )
v4std := getv4stdRR ( )
// if the dns map does not have a key for the request it will return an empty slice
v4non := getv4nonRR ( )
v4std := config . dns [ s . dnsHost + ".A" ]
v6std := getv6stdRR ( )
v4non := config . dns [ "nonstd." + s . dnsHost + ".A" ]
v6non := getv6nonRR ( )
v6std := config . dns [ s . dnsHost + ".AAAA" ]
v6non := config . dns [ "nonstd." + s . dnsHost + ".AAAA" ]
config . dnsmtx . RUnlock ( )
var v4stdstr , v4nonstr [ ] string
var v4stdstr , v4nonstr [ ] string
var v6stdstr , v6nonstr [ ] string
var v6stdstr , v6nonstr [ ] string
@ -174,26 +187,37 @@ func statusNGHandler(w http.ResponseWriter, r *http.Request) {
type webstatus struct {
type webstatus struct {
Key string
Key string
Value string
Value string
Seeder string
}
}
func statusHandler ( w http . ResponseWriter , r * http . Request , status uint32 ) {
func statusHandler ( w http . ResponseWriter , r * http . Request , status uint32 ) {
startT := time . Now ( )
startT := time . Now ( )
// read the seeder name
n := r . FormValue ( "s" )
s := getSeederByName ( n )
if s == nil {
writeHeader ( w , r )
fmt . Fprintf ( w , "No seeder found called %s" , html . EscapeString ( n ) )
writeFooter ( w , r , startT )
return
}
// gather all the info before writing anything to the remote browser
// gather all the info before writing anything to the remote browser
ws := generateWebStatus ( status )
ws := generateWebStatus ( s , s tatus)
st := `
st := `
< center >
< center >
< table border = 1 >
< table border = 1 >
< tr >
< tr >
< th > Twistee < / th >
< th > Nod e< / th >
< th > Summary < / th >
< th > Summary < / th >
< / tr >
< / tr >
{ { range . } }
{ { range . } }
< tr >
< tr >
< td >
< td >
< a href = "/twistee?tw ={{.Key}}" > { { . Key } } < / a >
< a href = "/node?s={{.Seeder}}&nd ={{.Key}}" > { { . Key } } < / a >
< / td >
< / td >
< td >
< td >
{ { . Value } }
{ { . Value } }
@ -207,18 +231,18 @@ func statusHandler(w http.ResponseWriter, r *http.Request, status uint32) {
writeHeader ( w , r )
writeHeader ( w , r )
if len ( ws ) == 0 {
if len ( ws ) == 0 {
fmt . Fprintf ( w , "No Twiste es found with this status" )
fmt . Fprintf ( w , "No Nod es found with this status" )
} else {
} else {
switch status {
switch status {
case statusRG :
case statusRG :
fmt . Fprintf ( w , "<center><b>Twiste e Status: statusRG - (Reported Good) Have not been able to get addresses yet</b></center>" )
fmt . Fprintf ( w , "<center><b>Nod e Status: statusRG - (Reported Good) Have not been able to get addresses yet</b></center>" )
case statusCG :
case statusCG :
fmt . Fprintf ( w , "<center><b>Twiste e Status: statusCG - (Currently Good) Able to connect and get addresses</b></center>" )
fmt . Fprintf ( w , "<center><b>Nod e Status: statusCG - (Currently Good) Able to connect and get addresses</b></center>" )
case statusWG :
case statusWG :
fmt . Fprintf ( w , "<center><b>Twiste e Status: statusWG - (Was Good) Was Ok but now can not get addresses</b></center>" )
fmt . Fprintf ( w , "<center><b>Nod e Status: statusWG - (Was Good) Was Ok but now can not get addresses</b></center>" )
case statusNG :
case statusNG :
fmt . Fprintf ( w , "<center><b>Twiste e Status: statusNG - (No Good) Unable to get addresses</b></center>" )
fmt . Fprintf ( w , "<center><b>Nod e Status: statusNG - (No Good) Unable to get addresses</b></center>" )
}
}
t := template . New ( "Status template" )
t := template . New ( "Status template" )
t , err := t . Parse ( st )
t , err := t . Parse ( st )
@ -234,7 +258,59 @@ func statusHandler(w http.ResponseWriter, r *http.Request, status uint32) {
writeFooter ( w , r , startT )
writeFooter ( w , r , startT )
}
}
// copy Twistee details into a template friendly struct
// generateWebStatus is given a node status and returns a slice of webstatus structures
// ready to be ranged over by an html/template
func generateWebStatus ( s * dnsseeder , status uint32 ) ( ws [ ] webstatus ) {
s . mtx . RLock ( )
defer s . mtx . RUnlock ( )
var valueStr string
for k , v := range s . theList {
if v . status != status {
continue
}
switch status {
case statusRG :
valueStr = fmt . Sprintf ( "<b>Fail Count:</b> %v <b>DNS Type:</b> %s" ,
v . connectFails ,
v . dns2str ( ) )
case statusCG :
valueStr = fmt . Sprintf ( "<b>Remote Version:</b> %v%s <b>Last Block:</b> %v <b>DNS Type:</b> %s" ,
v . version ,
v . strVersion ,
v . lastBlock ,
v . dns2str ( ) )
case statusWG :
valueStr = fmt . Sprintf ( "<b>Last Try:</b> %s ago <b>Last Status:</b> %s\n" ,
time . Since ( v . lastTry ) . String ( ) ,
v . statusStr )
case statusNG :
valueStr = fmt . Sprintf ( "<b>Fail Count:</b> %v <b>Last Try:</b> %s ago <b>Last Status:</b> %s\n" ,
v . connectFails ,
time . Since ( v . lastTry ) . String ( ) ,
v . statusStr )
default :
valueStr = ""
}
ows := webstatus {
Key : k ,
Value : valueStr ,
Seeder : s . name ,
}
ws = append ( ws , ows )
}
return ws
}
// copy Node details into a template friendly struct
type webtemplate struct {
type webtemplate struct {
Key string
Key string
IP string
IP string
@ -257,16 +333,16 @@ type webtemplate struct {
Nonstdip string
Nonstdip string
}
}
// reflectHandler processes all requests and returns output in the requested format
// nodeHandler displays details about one node
func twiste eHandler( w http . ResponseWriter , r * http . Request ) {
func nod eHandler( w http . ResponseWriter , r * http . Request ) {
st := time . Now ( )
st := time . Now ( )
tw t := `
nd t := `
< center >
< center >
< table border = 1 >
< table border = 1 >
< tr >
< tr >
< th > Twiste e { { . Key } } < / th > < th > Details < / th >
< th > Nod e { { . Key } } < / th > < th > Details < / th >
< / tr >
< / tr >
< tr > < td > IP Address < / td > < td > { { . IP } } < / td > < / tr >
< tr > < td > IP Address < / td > < td > { { . IP } } < / td > < / tr >
< tr > < td > Port < / td > < td > { { . Port } } < / td > < / tr >
< tr > < td > Port < / td > < td > { { . Port } } < / td > < / tr >
@ -285,111 +361,68 @@ func twisteeHandler(w http.ResponseWriter, r *http.Request) {
< / table >
< / table >
< / center >
< / center >
`
`
s := config . seeder
// read the seeder name
n := r . FormValue ( "s" )
s := getSeederByName ( n )
if s == nil {
writeHeader ( w , r )
fmt . Fprintf ( w , "No seeder found called %s" , html . EscapeString ( n ) )
writeFooter ( w , r , st )
return
}
s . mtx . RLock ( )
s . mtx . RLock ( )
defer s . mtx . RUnlock ( )
defer s . mtx . RUnlock ( )
// skip the tw= from the raw query
k := r . FormValue ( "nd" )
k := html . UnescapeString ( r . URL . RawQuery [ 3 : ] )
writeHeader ( w , r )
writeHeader ( w , r )
if _ , ok := s . theList [ k ] ; ok == false {
if _ , ok := s . theList [ k ] ; ok == false {
fmt . Fprintf ( w , "Sorry there is no Twiste e with those details\n" )
fmt . Fprintf ( w , "Sorry there is no Nod e with those details\n" )
} else {
} else {
tw := s . theList [ k ]
nd := s . theList [ k ]
wt := webtemplate {
wt := webtemplate {
IP : tw . na . IP . String ( ) ,
IP : nd . na . IP . String ( ) ,
Port : tw . na . Port ,
Port : nd . na . Port ,
Dnstype : tw . dns2str ( ) ,
Dnstype : nd . dns2str ( ) ,
Nonstdip : tw . nonstdIP . String ( ) ,
Nonstdip : nd . nonstdIP . String ( ) ,
Statusstr : tw . statusStr ,
Statusstr : nd . statusStr ,
Lastconnect : tw . lastConnect . String ( ) ,
Lastconnect : nd . lastConnect . String ( ) ,
Lastconnectago : time . Since ( tw . lastConnect ) . String ( ) ,
Lastconnectago : time . Since ( nd . lastConnect ) . String ( ) ,
Lasttry : tw . lastTry . String ( ) ,
Lasttry : nd . lastTry . String ( ) ,
Lasttryago : time . Since ( tw . lastTry ) . String ( ) ,
Lasttryago : time . Since ( nd . lastTry ) . String ( ) ,
Crawlstart : tw . crawlStart . String ( ) ,
Crawlstart : nd . crawlStart . String ( ) ,
Crawlstartago : time . Since ( tw . crawlStart ) . String ( ) ,
Crawlstartago : time . Since ( nd . crawlStart ) . String ( ) ,
Connectfails : tw . connectFails ,
Connectfails : nd . connectFails ,
Crawlactive : tw . crawlActive ,
Crawlactive : nd . crawlActive ,
Version : tw . version ,
Version : nd . version ,
Strversion : tw . strVersion ,
Strversion : nd . strVersion ,
Services : tw . services . String ( ) ,
Services : nd . services . String ( ) ,
Lastblock : tw . lastBlock ,
Lastblock : nd . lastBlock ,
}
}
// display details for the Twiste e
// display details for the Nod e
t := template . New ( "Twiste e template" )
t := template . New ( "Nod e template" )
t , err := t . Parse ( tw t)
t , err := t . Parse ( nd t)
if err != nil {
if err != nil {
log . Printf ( "error parsing Twiste e template %v\n" , err )
log . Printf ( "error parsing Nod e template %v\n" , err )
}
}
err = t . Execute ( w , wt )
err = t . Execute ( w , wt )
if err != nil {
if err != nil {
log . Printf ( "error executing Twiste e template %v\n" , err )
log . Printf ( "error executing Nod e template %v\n" , err )
}
}
}
}
writeFooter ( w , r , st )
writeFooter ( w , r , st )
}
}
// generateWebStatus is given a twistee status and returns a slice of webstatus structures
// summaryHandler displays details about one node
// ready to be ranged over by an html/template
func summaryHandler ( w http . ResponseWriter , r * http . Request ) {
func generateWebStatus ( status uint32 ) ( ws [ ] webstatus ) {
s := config . seeder
s . mtx . RLock ( )
defer s . mtx . RUnlock ( )
var valueStr string
for k , v := range s . theList {
if v . status != status {
continue
}
switch status {
case statusRG :
valueStr = fmt . Sprintf ( "<b>Fail Count:</b> %v <b>DNS Type:</b> %s" ,
v . connectFails ,
v . dns2str ( ) )
case statusCG :
valueStr = fmt . Sprintf ( "<b>Remote Version:</b> %v%s <b>Last Block:</b> %v <b>DNS Type:</b> %s" ,
v . version ,
v . strVersion ,
v . lastBlock ,
v . dns2str ( ) )
case statusWG :
valueStr = fmt . Sprintf ( "<b>Last Try:</b> %s ago <b>Last Status:</b> %s\n" ,
time . Since ( v . lastTry ) . String ( ) ,
v . statusStr )
case statusNG :
st := time . Now ( )
valueStr = fmt . Sprintf ( "<b>Fail Count:</b> %v <b>Last Try:</b> %s ago <b>Last Status:</b> %s\n" ,
v . connectFails ,
time . Since ( v . lastTry ) . String ( ) ,
v . statusStr )
default :
valueStr = ""
}
ows := webstatus {
Key : k ,
Value : valueStr ,
}
ws = append ( ws , ows )
}
return ws
}
// genHeader will output the standard header
func writeHeader ( w http . ResponseWriter , r * http . Request ) {
var hc struct {
var hc struct {
Name string
RG uint32
RG uint32
RGS uint32
RGS uint32
CG uint32
CG uint32
@ -406,65 +439,85 @@ func writeHeader(w http.ResponseWriter, r *http.Request) {
DNSTotal uint32
DNSTotal uint32
}
}
writeHeader ( w , r )
// loop through each of the seeders
for _ , s := range config . seeders {
hc . Name = s . name
// fill the structs so they can be displayed via the template
// fill the structs so they can be displayed via the template
counts . mtx . RLock ( )
s . counts . mtx . RLock ( )
hc . RG = counts . TwStatus [ statusRG ]
hc . RG = s . counts . Nd Status[ statusRG ]
hc . RGS = counts . TwStarts [ statusRG ]
hc . RGS = s . counts . Nd Starts[ statusRG ]
hc . CG = counts . TwStatus [ statusCG ]
hc . CG = s . counts . Nd Status[ statusCG ]
hc . CGS = counts . Tw Starts[ statusCG ]
hc . CGS = s . counts . Nd Starts[ statusCG ]
hc . WG = counts . Tw Status[ statusWG ]
hc . WG = s . counts . Nd Status[ statusWG ]
hc . WGS = counts . Tw Starts[ statusWG ]
hc . WGS = s . counts . Nd Starts[ statusWG ]
hc . NG = counts . Tw Status[ statusNG ]
hc . NG = s . counts . Nd Status[ statusNG ]
hc . NGS = counts . Tw Starts[ statusNG ]
hc . NGS = s . counts . Nd Starts[ statusNG ]
hc . Total = hc . RG + hc . CG + hc . WG + hc . NG
hc . Total = hc . RG + hc . CG + hc . WG + hc . NG
hc . V4Std = counts . DNSCounts [ dnsV4Std ]
hc . V4Std = s . counts . DNSCounts [ dnsV4Std ]
hc . V4Non = counts . DNSCounts [ dnsV4Non ]
hc . V4Non = s . counts . DNSCounts [ dnsV4Non ]
hc . V6Std = counts . DNSCounts [ dnsV6Std ]
hc . V6Std = s . counts . DNSCounts [ dnsV6Std ]
hc . V6Non = counts . DNSCounts [ dnsV6Non ]
hc . V6Non = s . counts . DNSCounts [ dnsV6Non ]
hc . DNSTotal = hc . V4Std + hc . V4Non + hc . V6Std + hc . V6Non
hc . DNSTotal = hc . V4Std + hc . V4Non + hc . V6Std + hc . V6Non
counts . mtx . RUnlock ( )
s . counts . mtx . RUnlock ( )
// we are using basic and simple html here. No fancy graphics or css
// we are using basic and simple html here. No fancy graphics or css
h := `
sp := `
< ! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" >
< b > Stats for seeder : { { . Name } } < / b >
< html > < head > < title > dnsseeder < / title > < / head > < body >
< center >
< center >
< a href = "/statusRG" > statusRG < / a >
< a href = "/statusCG" > statusCG < / a >
< a href = "/statusWG" > statusWG < / a >
< a href = "/statusNG" > statusNG < / a >
< a href = "/dns" > DNS < / a >
< br >
< table > < tr > < td >
< table > < tr > < td >
Twiste e Stats ( count / started ) < br >
Node Stats ( count / started ) < br >
< table border = 1 > < tr >
< table border = 1 > < tr >
< td > RG : { { . RG } } / { { . RGS } } < / td > < td > CG : { { . CG } } / { { . CGS } } < / td > < td > WG : { { . WG } } / { { . WGS } } < / td > < td > NG : { { . NG } } / { { . NGS } } < / td > < td > Total : { { . Total } } < / td >
< td > < a href = "/statusRG?s={{.Name}}" > RG : { { . RG } } / { { . RGS } } < / a > < / td >
< td > < a href = "/statusCG?s={{.Name}}" > CG : { { . CG } } / { { . CGS } } < / a > < / td >
< td > < a href = "/statusWG?s={{.Name}}" > WG : { { . WG } } / { { . WGS } } < / a > < / td >
< td > < a href = "/statusNG?s={{.Name}}" > NG : { { . NG } } / { { . NGS } } < / a > < / td >
< td > Total : { { . Total } } < / td >
< / tr > < / table >
< / tr > < / table >
< / td > < td >
< / td > < td >
DNS Requests < br >
DNS Requests < br >
< table border = 1 > < tr >
< table border = 1 > < tr >
< td > V4 Std : { { . V4Std } } < / td > < td > V4 Non : { { . V4Non } } < / td > < td > V6 Std : { { . V6Std } } < / td > < td > V6 Non : { { . V6Non } } < / td > < td > Total : { { . DNSTotal } } < / td >
< td > V4 Std : { { . V4Std } } < / td >
< td > V4 Non : { { . V4Non } } < / td >
< td > V6 Std : { { . V6Std } } < / td >
< td > V6 Non : { { . V6Non } } < / td >
< td > < a href = "/dns?s={{.Name}}" > Total : { { . DNSTotal } } < / a > < / td >
< / tr > < / table >
< / tr > < / table >
< / td > < / tr > < / table >
< / td > < / tr > < / table >
< / center >
< / center >
< hr >
`
`
t := template . New ( "Header template" )
t := template . New ( "Header template" )
t , err := t . Parse ( h )
t , err := t . Parse ( sp )
if err != nil {
if err != nil {
log . Printf ( "error parsing template %v\n" , err )
log . Printf ( "error parsing summary template %v\n" , err )
}
}
err = t . Execute ( w , hc )
err = t . Execute ( w , hc )
if err != nil {
if err != nil {
log . Printf ( "error executing template %v\n" , err )
log . Printf ( "error executing summary template %v\n" , err )
}
}
writeFooter ( w , r , st )
}
}
// writeHeader will output the standard header
func writeHeader ( w http . ResponseWriter , r * http . Request ) {
// we are using basic and simple html here. No fancy graphics or css
h := `
< ! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" >
< html > < head > < title > dnsseeder < / title > < / head > < body >
< center >
< a href = "/summary" > Summary < / a >
< / center >
< hr >
< br >
`
fmt . Fprintf ( w , h )
}
}
// genFooter will output the standard footer
// write Footer will output the standard footer
func writeFooter ( w http . ResponseWriter , r * http . Request , st time . Time ) {
func writeFooter ( w http . ResponseWriter , r * http . Request , st time . Time ) {
// Footer needs to be exported for template processing to work
// Footer needs to be exported for template processing to work
@ -483,7 +536,7 @@ func writeFooter(w http.ResponseWriter, r *http.Request, st time.Time) {
< / center >
< / center >
< / body > < / html >
< / body > < / html >
`
`
Footer . Uptime = time . Since ( config . seeder . uptime ) . String ( )
Footer . Uptime = time . Since ( config . uptime ) . String ( )
Footer . Version = config . version
Footer . Version = config . version
Footer . Rt = time . Since ( st ) . String ( )
Footer . Rt = time . Since ( st ) . String ( )