@@ -8,29 +8,14 @@ import (
88 "strings"
99)
1010
11- type Flags struct {
12- browser bool
13- Device bool
14- os bool
15- }
16-
17- // New creates a new instance of Udger and load all the database in memory to allow fast lookup
18- // you need to pass the sqlite database in parameter
19- func New (dbPath string , flags * Flags ) (* Udger , error ) {
20- if flags == nil {
21- flags = & Flags {
22- browser : true ,
23- Device : true ,
24- os : true ,
25- }
26- }
11+ // New creates a new instance of Udger from the dbPath database loaded in memory for fast lookup.
12+ func New (dbPath string ) (* Udger , error ) {
2713 u := & Udger {
2814 Browsers : make (map [int ]Browser ),
2915 OS : make (map [int ]OS ),
3016 Devices : make (map [int ]Device ),
3117 browserTypes : make (map [int ]string ),
3218 browserOS : make (map [int ]int ),
33- Flags : flags ,
3419 }
3520 var err error
3621
@@ -52,66 +37,57 @@ func New(dbPath string, flags *Flags) (*Udger, error) {
5237 return u , nil
5338}
5439
55- // Lookup one user agent and return a Info struct who contains all the metadata possible for the UA .
40+ // Lookup returns all the metadata possible for the given user agent string ua .
5641func (udger * Udger ) Lookup (ua string ) (* Info , error ) {
5742 info := & Info {}
58- f := udger .Flags
5943
60- var browserID int
61- if f .browser {
62- browserID , version , err := udger .findDataWithVersion (ua , udger .rexBrowsers , true )
63- if err != nil {
64- return nil , err
65- }
66- info .Browser = udger .Browsers [browserID ]
44+ browserID , browserVersion := udger .findDataWithVersion (ua , udger .rexBrowsers , true )
45+ if browser , found := udger .Browsers [browserID ]; found {
46+ info .Browser = browser
6747 if info .Browser .Family != "" {
68- info .Browser .Name = info . Browser . Family + " " + version
48+ info .Browser .Name = browser . Family + " " + browserVersion
6949 }
70- info .Browser .Version = version
71- info .Browser .Type = udger .browserTypes [info .Browser .typ ]
50+ info .Browser .Version = browserVersion
51+ info .Browser .Type = udger .browserTypes [browser .typ ]
52+ } else {
53+ info .Browser .typ = - 1
7254 }
7355
74- if f .os {
75- if val , ok := udger .browserOS [browserID ]; ok {
76- info .OS = udger .OS [val ]
77- } else {
78- osID , _ , err := udger .findData (ua , udger .rexOS , false )
79- if err != nil {
80- return nil , err
81- }
82- info .OS = udger .OS [osID ]
83- }
56+ if val , ok := udger .browserOS [browserID ]; ok {
57+ info .OS = udger .OS [val ]
58+ } else {
59+ osID , _ := udger .findDataWithVersion (ua , udger .rexOS , false )
60+ info .OS = udger .OS [osID ]
8461 }
8562
86- if f .Device {
87- deviceID , _ , err := udger .findData (ua , udger .rexDevices , false )
88- if err != nil {
89- return nil , err
63+ deviceID , _ := udger .findDataWithVersion (ua , udger .rexDevices , false )
64+
65+ if val , ok := udger .Devices [deviceID ]; ok {
66+ info .Device = val
67+ } else if info .Browser .typ == - 1 { // empty
68+ // pass
69+ } else if info .Browser .typ == 3 { // if browser is mobile, we can guess it's a mobile
70+ info .Device = Device {
71+ Name : "Smartphone" ,
72+ Icon : "phone.png" ,
9073 }
91- if val , ok := udger .Devices [deviceID ]; ok {
92- info .Device = val
93- } else if info .Browser .typ == 3 { // if browser is mobile, we can guess its a mobile
94- info .Device = Device {
95- Name : "Smartphone" ,
96- Icon : "phone.png" ,
97- }
98- } else if info .Browser .typ == 5 || info .Browser .typ == 10 || info .Browser .typ == 20 || info .Browser .typ == 50 {
99- info .Device = Device {
100- Name : "Other" ,
101- Icon : "other.png" ,
102- }
103- } else {
104- //nothing so personal computer
105- info .Device = Device {
106- Name : "Personal computer" ,
107- Icon : "desktop.png" ,
108- }
74+ } else if info .Browser .typ == 5 || info .Browser .typ == 10 || info .Browser .typ == 20 || info .Browser .typ == 50 {
75+ info .Device = Device {
76+ Name : "Other" ,
77+ Icon : "other.png" ,
78+ }
79+ } else {
80+ //nothing so personal computer
81+ info .Device = Device {
82+ Name : "Personal computer" ,
83+ Icon : "desktop.png" ,
10984 }
11085 }
11186 return info , nil
11287}
11388
11489func (udger * Udger ) cleanRegex (r string ) string {
90+ // removes single-line and case-insensitive modifiers
11591 if strings .HasSuffix (r , "/si" ) {
11692 r = r [:len (r )- 3 ]
11793 }
@@ -122,47 +98,35 @@ func (udger *Udger) cleanRegex(r string) string {
12298 return r
12399}
124100
125- func (udger * Udger ) findDataWithVersion (ua string , data []rexData , withVersion bool ) (idx int , value string , err error ) {
126- defer func () {
127- if r := recover (); r != nil {
128- idx , value , err = udger .findData (ua , data , false )
129- }
130- }()
131- idx , value , err = udger .findData (ua , data , withVersion )
132- return idx , value , err
133- }
134-
135- func (udger * Udger ) findData (ua string , data []rexData , withVersion bool ) (idx int , value string , err error ) {
101+ func (udger * Udger ) findDataWithVersion (ua string , data []rexData , withVersion bool ) (int , string ) {
102+ index := - 1
103+ version := ""
136104 for i := 0 ; i < len (data ); i ++ {
137105 r := data [i ].RegexCompiled
138106 if ! r .MatchString (ua ) {
139107 continue
140108 }
141- //TODO: implement with regexp lib for support browser version & name
142- //if withVersion && matcher.Present(1) {
143- // return data[i].ID, matcher.GroupString(1), nil
144- //}
145- return data [i ].ID , "" , nil
109+ index = data [i ].ID
110+ if withVersion {
111+ sub := r .FindStringSubmatch (ua )
112+ if len (sub ) >= 2 {
113+ version = sub [1 ]
114+ }
115+ }
116+ break
146117 }
147- return - 1 , "" , nil
118+ return index , version
148119}
149120
150121func (udger * Udger ) init () error {
151- f := udger .Flags
152- if f .browser {
153- if err := udger .initBrowsers (); err != nil {
154- return err
155- }
122+ if err := udger .initBrowsers (); err != nil {
123+ return err
156124 }
157- if f .Device {
158- if err := udger .initDevices (); err != nil {
159- return err
160- }
125+ if err := udger .initDevices (); err != nil {
126+ return err
161127 }
162- if f .os {
163- if err := udger .initOS (); err != nil {
164- return err
165- }
128+ if err := udger .initOS (); err != nil {
129+ return err
166130 }
167131 return nil
168132}
@@ -176,6 +140,7 @@ func (udger *Udger) initBrowsers() error {
176140 var d rexData
177141 rows .Scan (& d .ID , & d .Regex )
178142 d .Regex = udger .cleanRegex (d .Regex )
143+ // set case-insensitive flag withing current group
179144 r , err := regexp .Compile ("(?i)" + d .Regex )
180145 if err != nil {
181146 return err
@@ -185,6 +150,7 @@ func (udger *Udger) initBrowsers() error {
185150 }
186151 rows .Close ()
187152
153+ // Chrome, Safari, Firefox, etc.
188154 rows , err = udger .db .Query ("SELECT id, class_id, name,engine,vendor,icon FROM udger_client_list" )
189155 if err != nil {
190156 return err
@@ -197,6 +163,7 @@ func (udger *Udger) initBrowsers() error {
197163 }
198164 rows .Close ()
199165
166+ // browser, mobile, crawler, etc.
200167 rows , err = udger .db .Query ("SELECT id, client_classification FROM udger_client_class" )
201168 if err != nil {
202169 return err
0 commit comments