Giter Site home page Giter Site logo

device_detector's People

Contributors

aried3r avatar axeleander avatar benzimmer avatar brunoarueira avatar dirk82 avatar dnswus avatar girardof avatar igor-drozdov avatar madejejej avatar matisojka avatar mkdynamic avatar n-rodriguez avatar opti avatar seandilda avatar skaes avatar spiderpug avatar steverob avatar yagooar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

device_detector's Issues

device_type is nil for UserAgent from Wechat Brower

the user agent like

"Mozilla/5.0 (Linux; Android 5.1; MX5 Build/LMY47I; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/53.0.2785.49 Mobile MQQBrowser/6.2 TBS/043015 Safari/537.36 MicroMessenger/6.5.3.980 NetType/4G Language/zh_CN"

and the device_type is nil

Usage from README.md doesn't work

This gem seems so promising!

I looked into this for a few minutes, but couldn't determine the problem. Here's what I ran in irb:

2.1.5 :001 > require 'device_detector'
 => true 
2.1.5 :002 > user_agent = 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36'
 => "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36" 
2.1.5 :003 > client = DeviceDetector.new(user_agent)
 => #<DeviceDetector:0x007fab345a3b10 @user_agent="Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36"> 
2.1.5 :004 > client.name
 => "Chrome" 
2.1.5 :005 > client.full_version
 => "30.0.1599.17" 
2.1.5 :006 > client.os_name
 => "Windows" 
2.1.5 :007 > client.os_full_version
 => "8" 
2.1.5 :008 > client.device_name
 => "OW64" 
2.1.5 :009 > client.device_type
 => "tv" 

nil user-agent string causes raise in 1.1.0

In device_detector 1.0.7

DeviceDector.new(nil).device_name # => nil

In device_detector 1.1.0

 DeviceDector.new(nil).device_name 

raises

gems/device_detector-1.1.0/lib/device_detector.rb:221:in fix_for_x_music': undefined method include?' for nil:NilClass (NoMethodError)

This seems like maybe an unintended backwards incompatible change, that may break some dependents that aren't prepared for it?

The easy workaround seems to be to make sure you never pass nil to DeviceDector.new; passing an empty string is fine, so DeviceDector.new(str_var || "") might be the way to go.

But perhaps DeviceDetector should handle this itself?

Encoding::CompatibilityError caused by "é" in User-Agent

Hi! I've encountered Encoding::CompatibilityError in my project caused by non-standard characters in a custom User-Agent.

Environment: Ruby 3.2.0, DeviceDetector 1.1.0.
Environment: Ruby 3.0.2, DeviceDetector 1.1.0.

User's agent is Mon User-Agent personnalisé.

The error:
Encoding::CompatibilityError (incompatible encoding regexp match (UTF-8 regexp with ASCII-8BIT string))

It seems to be caused by user_agent =~ r[:regex] in device.rb's regex_find

regex_list.find { |r| user_agent =~ r[:regex] }

I see that it already rescues RegexpError. I was wondering if Encoding::CompatibilityError stands to be rescued here as well. I've forked the gem and made the change for my project and it no longer raises an error with this User-Agent, removing the last char instead.

Any thoughts on this?

Trace:

device_detector (1.1.0) lib/device_detector/device.rb in each at line 1560
device_detector (1.1.0) lib/device_detector/device.rb in find at line 1560
device_detector (1.1.0) lib/device_detector/device.rb in regex_find at line 1560
device_detector (1.1.0) lib/device_detector/device.rb in block in matching_regex at line 1535
device_detector (1.1.0) lib/device_detector/parser.rb in block in from_cache at line 92
device_detector (1.1.0) lib/device_detector/memory_cache.rb in get_or_set at line 38
device_detector (1.1.0) lib/device_detector/parser.rb in from_cache at line 92
device_detector (1.1.0) lib/device_detector/device.rb in matching_regex at line 1531
device_detector (1.1.0) lib/device_detector/parser.rb in regex_meta at line 31
device_detector (1.1.0) lib/device_detector/device.rb in type at line 1505
device_detector (1.1.0) lib/device_detector.rb in device_type at line 67

Getting brand name for mobiles

How to detect brand name for mobile? There has a device_name field but mostly it shows only the device model and can't detect phone brands such as Samsung, Mi etc...

Weird OS Parsing

When parsing a user_agent for Chrome on Mac OSX 10.10.2, the os_full_version is returned as 10_10_2 instead of 10.10.2

Last regexes and fixtures for device-detector, tests not passing

Hello, due to the number of changes in the device-detector original library, even if I run the rake tasks for updating the YAML files, the tests do not pass.

I have seen that some fixes have been added to the library so that is presumably the reason why the tests do not pass. I tried to change some results expected as "" but returned as nil and vice versa, but I could not get all the tests passed, so I think the best would be to start adding those fixes to this Ruby implementation of the library.

I am willing to contribute, I will start adding some pull requests.

Thanks and congratulations for the excellent library.

What do people use for a hosting network detector?

I'm wondering what people use for detecting hosting networks or networks likely to have bots? I see that Amazon advertise their IP address ranges via JSON. Would there be an interest in adding that functionality to this gem? Provided we could find enough network ranges that is.

Shutdown cache

Hi,

We are encountering an issue that some requests are hanging or even timing out, and our thought is that it has to do with our high load and the device_detector library as it always happens before our first db call which only has the device detection before it. and then specifically caused by the Mutex locking.

Our servers are running with puma and concurrency. but more important, none of the user agents in the time frame of 5000 cached keys is expected to be equal or very little ones.

Is setting the cache amount to 0 enough? or will this break the caching option?

what do you suggest/think?

Kind regards,
Stephan

Android 9 user agents get nil as os_full_version

Now that android 9 is live, the user agents we get from those devices look something like this:

Mozilla/5.0 (Linux; Android 9; Pixel 2 XL Build/PPP3.180510.008; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/67.0.3396.87 Mobile Safari/537.36
                            ^
                            This is where we should see something like 9.0 instead

(as seen here)

Because the regexp for android devices expects a version number like
(\d+[\.\d]+) The lone 9 is just not picked up.

You can reproduce it like this:

dd = DeviceDetector.new "Mozilla/5.0 (Linux; Android 9; Pixel 2 Build/PPR1.180610.009) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Mobile Safari/537.36"
dd.os_full_version # => nil

open os family method

Hi, @peteygao

Great gem, I want to replace user_agent.

But I face a small problem now, I want to get os.family and find it private.

Do you have plan to open the information? Thank you very much.

No git tags?

Hi there! It would be nice to have git tags matching with gem releases. Thank you!

Unable to detect Firefox Android

Hello,

I have the following user agent : "Mozilla/5.0 (Android 7.1.2; Mobile; rv:55.0.2) Gecko/55.0.2 Firefox/55.0.2"

It can't detect that I am using a smartphone but it detect that I'm using Android..

device = DeviceDetector.new("Mozilla/5.0 (Android 7.1.2; Mobile; rv:55.0.2) Gecko/55.0.2 Firefox/55.0.2")
device.device_type
=> nil
device.os_name
=> "Android"

Is this gem still maintained?

I see that regexes from original repository has been imported last time at 2022-02-17 (8 months ago at a time when I'm writing this) so I'd like to ask if this gem is still maintained by author and if updates can be expected in future?

Fails to identify device from user_agent string

Device_name returns nil for user_agent string
'Mozilla/5.0 (Linux; Android 5.1.1; ONE E1003 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.95 Mobile Safari/537.36'

but returns proper OS info:

> c = DeviceDetector.new 'Mozilla/5.0 (Linux; Android 5.1.1; ONE E1003 Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.95 Mobile Safari/537.36'
> c.device_name
=> nil
> c.device_brand
=> nil
> c.os_name
=> "Android"
> c.os_full_version
=> "5.1.1"

Benchmarks need a little clarification and maybe a feature request

Please correct me if I'm wrong... The actual parsing of the UA string does not take place until a specific component is requested. At that point only that specific component is extracted from the UA string. So other user agent parsers which extract all components at once will show up slower in your benchmarks.

I can see where your JIT parser approach comes in handy when only one or two components are used within an application. it would be interesting to see how your approach actually compares to a full parse of all components. For example Useragent now supports a #to_h method which provides a nicely structured representation of all of the components of the UA string.

If DeviceDetector had a #to_h feature that did the same thing, how would your regex approach compare benchmark-wise against UserAgent ?

I can see how a #to_h feature may be outside the scope for which DeviceDetector is best suited.

Dewayne
o-*

Update to the latest regex of original Piwik

Hi, first thanks for this wonderful and powerful gem.

We run into an issue that took a long time to understand.

Actually we found out that the reason our app has wrong behavior is sue to device detector gem.
Indeed on UC browsers, the original Piwik fixed the issue in order not to output "Chrome" but UC Browser a major browser (in Asia notably).
See matomo-org/device-detector#5617

But in our tests on various UC Browsers, for example on the user agent below, the original piwik after their fix now righfully output client name =uc browser, but ruby device Detector Gem still wrongly output "Chrome"

User agent example
Mozilla/5.0 (Linux; U; Android 4.2.2;en-US;Darkmoon Build Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.0.0.1088 Mobile Safari/537.36

I think it's due to the fact the folder regexes was last updated 11 months ago but the fix in the piwik yaml regexes was done in may 2017, which is before those 11 months.

Is is easy to fix ?

Thanks
M.

warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression

Hi! This gem is currently being used as a dependency, and I noticed a gem specific warning that pops up when device_detector is initialized.

Specifically:
warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression AND
regular expression has ']' without escape

It looks like the issue is stemming from this file on line 88.

I don't know a ton about Regexp and would probably have a difficult time trying to solve this.

Thanks!

.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/device_detector-1.0.6/lib/device_detector/parser.rb:88: warning: regular expression has ']' without escape
/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/device_detector-1.0.6/lib/device_detector/parser.rb:88: warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression
/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/device_detector-1.0.6/lib/device_detector/parser.rb:88: warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression
/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/device_detector-1.0.6/lib/device_detector/parser.rb:88: warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression
/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/device_detector-1.0.6/lib/device_detector/parser.rb:88: warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression
/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/device_detector-1.0.6/lib/device_detector/parser.rb:88: warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression
/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/device_detector-1.0.6/lib/device_detector/parser.rb:88: warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression
/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/device_detector-1.0.6/lib/device_detector/parser.rb:88: warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression
/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/device_detector-1.0.6/lib/device_detector/parser.rb:88: warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression

Unable to detect Firefox android device_type and newly launched devices

user_agent = 'Mozilla/5.0 (Android:9; Mobile; rv:67) Gecko/67.0 Firefox/67.0'
=> "Mozilla/5.0 (Android:9; Mobile; rv:67) Gecko/67.0 Firefox/67.0"
client = DeviceDetector.new(user_agent)
=> #<DeviceDetector:0x007fd28ab04d20 @user_agent="Mozilla/5.0 (Android:9; Mobile; rv:67) Gecko/67.0 Firefox/67.0">
[14] pry(main)> client.os_name
=> "Android"
pry(main)> client.name
=> "Firefox Mobile"
[15] pry(main)> client.device_type
=> nil
pry(main)> client.device_name
=> nil

Parsing user_agent for symbian os

Hello, i created issue in original library here
It looks, that device_detector on this user agent string returns nil

Mozilla/4.0 (compatible; MSIE 6.0; Symbian OS; Series 60/03.83; 9730) Opera 8.65 [ru]

Are you really sure, that regexpes in device_detector gem is really new?

[safely] incompatible encoding regexp match (UTF-8 regexp with ASCII-8BIT string)

/gems/device_detector-1.1.0/lib/device_detector/device.rb:1560 in block in regex_find
/gems/device_detector-1.1.0/lib/device_detector/device.rb:1560 in each
/gems/device_detector-1.1.0/lib/device_detector/device.rb:1560 in find
/gems/device_detector-1.1.0/lib/device_detector/device.rb:1560 in regex_find
/gems/device_detector-1.1.0/lib/device_detector/device.rb:1535 in block in matching_regex
/gems/device_detector-1.1.0/lib/device_detector/parser.rb:92 in block in from_cache
/gems/device_detector-1.1.0/lib/device_detector/memory_cache.rb:38 in get_or_set
/gems/device_detector-1.1.0/lib/device_detector/parser.rb:92 in from_cache
/gems/device_detector-1.1.0/lib/device_detector/device.rb:1531 in matching_regex
/gems/device_detector-1.1.0/lib/device_detector/parser.rb:31 in regex_meta
/gems/device_detector-1.1.0/lib/device_detector/device.rb:1505 in type
/gems/device_detector-1.1.0/lib/device_detector.rb:67 in device_type
/gems/ahoy_matey-4.1.0/lib/ahoy/base_store.rb:59 in bot?
/gems/ahoy_matey-4.1.0/lib/ahoy/base_store.rb:39 in exclude?
/gems/ahoy_matey-4.1.0/lib/ahoy/tracker.rb:189 in exclude?
/gems/ahoy_matey-4.1.0/lib/ahoy/tracker.rb:20 in track
app/controllers/application_controller.rb:14 in track_action
12:
    properties[:method] = request.method
13:
14:
    ahoy.track request.fullpath, properties
15:
  end
16:
end

browser is said to be mobile safari when using an app on an iPad

When using an app on an iOS, the browser is set correctly, however once the OS in the user agent changes to iPadOS, then the browser is set to be recognised as a mobile safari even though the app is still being used.

e.g.
<app_name>/3.7.1 (iPad; iPadOS 15.6.1; Scale/2.00)/ DeviceId/48C8426D-64B6-4961-BD3E-09FD99C3B046/ BuildNumber/1111 returns browser as "Mobile Safari" but
<app_name>/3.7.1 (iPad; iOS 15.6.1; Scale/2.00)/ DeviceId/48C8426D-64B6-4961-BD3E-09FD99C3B046/ BuildNumber/1111 returns browser as "<app_name>"

Similar thing happens with android where the browser on an android device returns "Android Browser" even though the app name is specified

At the moment I have a hack in place that checks for the app name at the beginning of the user agent string but that is just a hack and I would prefer not to make use of it for long. I'll tinker with this library if I have some time, just thought I would report this issue 🥺

Use RuboCop?

Hi @spiderpug,

Thanks for maintaining this so far!
However, there are a bunch of things that could be fixed according to the Ruby style guide.

Would you consider using RuboCop?
I would be happy to raise a PR if so :)

Outdated regexes

Is this library still being maintained? The last PR to update regexes was in 2020 and it was still not merged.

Any active forks?

Ruby warnings

Hi there!

Since release 1.0.6 I get this warning :

/cache/nicolas/concerto/ruby-master/ruby/3.0.0/gems/device_detector-1.0.6/lib/device_detector/parser.rb:88: warning: regular expression has ']' without escape
/cache/nicolas/concerto/ruby-master/ruby/3.0.0/gems/device_detector-1.0.6/lib/device_detector/parser.rb:88: warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression

Thank you!

Old Ubuntu user agent parsing seems incorrect

Obvious from looking at oss.yml why this is so, but I have what I believe to be a legitimate user agent string from an old version of Ubuntu that is failing the following test:

def test_ubuntu_10_device_detector
  agent_string = 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.133 Chrome/10.0.648.133 Safari/534.16'

  uap = UserAgentParser::Parser.new.parse(agent_string)
  assert_equal 'Ubuntu 10.10', uap.os.to_s # UAP seemingly has rules to match this

  dd = DeviceDetector.new(agent_string)
  assert_equal 'Ubuntu', dd.os_name
end

Test output:

  1) Failure:
ImprovedUserAgentTest#test_ubuntu_10_device_detector [test/models/user_agent_test.rb:15]:
Expected: "Ubuntu"
  Actual: "$1"

Upstream patterns can't be updated due to Ruby Regex error

When updating to latest upstream regexes tests are failing for a string with special charater, eg:

6) Error:
DeviceDetector::smartphone-7.yml::Mozilla/5.0 (Linux; U; Android 2.3.6; pt-br; XT321 Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Versão/4.0 Mobile Safari/533.1#test_0001_should be detected:
RegexpError: invalid pattern in look-behind: /(?:^|[^A-Z0-9\-_]|[^A-Z0-9\-]_|sprd-)(?:acer|(?<!ZTE BLADE |ImSmart |ERGO |X-Style Tab )a(?:101|110|2[10]0|211|50[10]|51[10]|70[10])[);\/ ]|Android.*V3[67]0[);\/ ]|Android.*Z1[23456]0 Build|Android.*Z5\d{2} Build|Android.*T0[234678] Build|Android.*S55[);\/ ]|A1-830|A1-81[01]|A1-7[23]4|A3-A[1234][01]|B1-7[1235678][01]|B1-7[23]3|B1-8[1235]0|B1-A71|B3-A[12]0|B3-A3[02]|E39[);\/ ]|S5[12]0 Build|DA[0-9]+HQ?L[);\/ ]|Aspire V5-121|Predator G9-793|GT-810)/i

Source regexp that is causing the issue:
https://github.com/matomo-org/device-detector/blob/118651c4fbff739e7f29acebd1732e7ccbf238a7/regexes/device/mobiles.yml#L735

This seems to be related to a bug in Ruby Regexp
https://bugs.ruby-lang.org/issues/13671

Until the problem is fixed a workaround needs to be implemented. One quick option would be to fail silently when this happens, but that's obviously not a good solution. Any ideas?

When using Chrome on a MacBook - returned info is incorrect

So when running in development, (have not tried it in prod as of yet), When I capture the client data in my password reset controller, info is returning as incorrect? this is how I have implemented the call (it will be refactored later).

  def create
    user_agent = 'Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36'
    client = DeviceDetector.new(user_agent)
    @user = User.find_by(email: params[:password_reset][:email].downcase)
    if @user
      @user.create_reset_digest
      PasswordResetDetail.create(
        user_id: @user.id,
        client_name: client.name,
        client_full_version: client.full_version,
        client_os_name: client.os_name,
        client_os_full_version: client.os_full_version,
        client_device_name: client.device_name,
        client_device_type: client.device_type,
        client_is_known: client.known?
      )
      UserMailer.password_reset(@user).deliver_now
      flash[:info] = 'Email sent with password reset instructions'
      redirect_to community_root_url(subdomain: 'community')
    else
      flash.now[:error] = 'Email address not found'
      render 'new'
    end
  end

This is the server output (no errors and aside from the wrong info it works very well!)

Started POST "/password_resets" for 127.0.0.1 at 2020-09-08 16:58:22 -0600
Processing by PasswordResetsController#create as HTML
  Parameters: {"authenticity_token"=>"JAJSpUbqzRKIS/nJ3QO+TFhh8stBF0BzRHdiaDHHpKizKLoAVEY8BhfIRfFlj4o4l6GDbJn4fFVmjOc+/bXWTw==", "password_reset"=>"[FILTERED]"}
  User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."email" = $1 LIMIT $2  [["email", "[email protected]"], ["LIMIT", 1]]
  ↳ app/controllers/password_resets_controller.rb:11:in `create'
   (0.2ms)  BEGIN
  ↳ app/models/user.rb:53:in `create_reset_digest'
  User Update (0.4ms)  UPDATE "users" SET "reset_digest" = $1, "updated_at" = $2 WHERE "users"."id" = $3  [["reset_digest", "$2a$12$z9FXWm6sgdYkwCUfhq5ntunOg5yEBFuCdQ8Cd1mUZ44xD5yHI1R9C"], ["updated_at", "2020-09-08 22:58:22.658982"], ["id", 1]]
  ↳ app/models/user.rb:53:in `create_reset_digest'
   (0.8ms)  COMMIT
  ↳ app/models/user.rb:53:in `create_reset_digest'
   (0.1ms)  BEGIN
  ↳ app/models/user.rb:54:in `create_reset_digest'
  User Update (0.5ms)  UPDATE "users" SET "updated_at" = $1, "reset_sent_at" = $2 WHERE "users"."id" = $3  [["updated_at", "2020-09-08 22:58:22.663686"], ["reset_sent_at", "2020-09-08 22:58:22.663494"], ["id", 1]]
  ↳ app/models/user.rb:54:in `create_reset_digest'
   (0.4ms)  COMMIT
  ↳ app/models/user.rb:54:in `create_reset_digest'
   (0.2ms)  BEGIN
  ↳ app/controllers/password_resets_controller.rb:14:in `create'
  User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/password_resets_controller.rb:14:in `create'
  PasswordResetDetail Create (0.4ms)  INSERT INTO "password_reset_details" ("user_id", "client_name", "client_full_version", "client_os_name", "client_os_full_version", "client_device_type", "client_is_known", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id"  [["user_id", 1], ["client_name", "Chrome"], ["client_full_version", "30.0.1599.17"], ["client_os_name", "Windows"], ["client_os_full_version", "8"], ["client_device_type", "desktop"], ["client_is_known", true], ["created_at", "2020-09-08 22:58:22.671077"], ["updated_at", "2020-09-08 22:58:22.671077"]]
  ↳ app/controllers/password_resets_controller.rb:14:in `create'
   (0.4ms)  COMMIT
  ↳ app/controllers/password_resets_controller.rb:14:in `create'
  PasswordResetDetail Load (0.5ms)  SELECT "password_reset_details".* FROM "password_reset_details" WHERE "password_reset_details"."user_id" = $1 ORDER BY "password_reset_details"."id" DESC LIMIT $2  [["user_id", 1], ["LIMIT", 1]]
  ↳ app/mailers/user_mailer.rb:31:in `password_reset'
  CACHE PasswordResetDetail Load (0.1ms)  SELECT "password_reset_details".* FROM "password_reset_details" WHERE "password_reset_details"."user_id" = $1 ORDER BY "password_reset_details"."id" DESC LIMIT $2  [["user_id", 1], ["LIMIT", 1]]
  ↳ app/mailers/user_mailer.rb:32:in `password_reset'
UserMailer#password_reset: processed outbound mail in 4.8ms
Breadcrumb ActionMail delivered meta_data from:Mail::AddressContainer has been dropped for having an invalid data type
Breadcrumb ActionMail delivered meta_data date:DateTime has been dropped for having an invalid data type
Delivered mail [email protected] (381.5ms)
Date: Tue, 08 Sep 2020 16:58:22 -0600
From: [email protected]
Reply-To: [email protected]
To: [email protected]
Message-ID: <[email protected]>
Subject: Postmark Template: "user-password-reset"
Mime-Version: 1.0
Content-Type: text/plain;
 charset=UTF-8
Content-Transfer-Encoding: 7bit
postmark-template-alias: user-password-reset

This message is using a Postmark template.

Alias: "user-password-reset"
Model:
{
  "name": "xxxx",
  "action_url": "http://community.lvh.me:3000/password_resets/0sScCHal3P7Zu_1xHfJWdA/edit?email=xxx%xxx-xxx-xxx.com",
  "device_name": "Desktop",
  "operating_system": "Windows",
  "support_url": "[email protected]"
}

Use the #prerender method on this object to contact the Postmark API to pre-render the template.

Cheers,
Your friends at Postmark
Redirected to http://community.lvh.me:3000/
Completed 302 Found in 684ms (ActiveRecord: 4.8ms | Allocations: 15911)

]

I am currently running a macbook pro, with macOS Catalina (v10.15.6)

Is my implementation buggered up or am I doing something wrong?

Old TV not recognised

This user agent OS and device name is not recognised

SAMSUNG-GT-E2152/E2152XXJK2 NetFront/3.5 Profile/MIDP-2.0 Configuration/CLDC-1.1

Tests not passing after updating regexes and fixtures

Hello, I have just run the tasks for updating regexes and fixtures in order to fix some user agents not recognising the device type. This is now fixed, the device type is recognised as expected, however, the rests are failing.

I would like to get my hands on them and fix them, but I was wondering if that's the right way or you usually follow other approach.

Thanks.

Benchmark in the Readme is outdated

I've ran benchmark from the Readme on my set of real user agents (160k) and it seems that the browser gem is much faster. I didn't compare precision of both though.

Could you compare them with your dataset again?

                      user     system      total        real
device_detector   4.713362   0.000000   4.713362 (  4.714573)
browser           1.780024   0.000000   1.780024 (  1.780048)

Failed device_brand method

DeviceDetector.new(Faker::Internet.user_agent).device_brand

device_detector/lib/device_detector/parser.rb:101:in `block in parse_regexes': no implicit conversion of Symbol into Integer (TypeError)

File structure is different

warnings on Readme's user agent sample

I was trying out your gem with the user agent from Readme which is:
Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.17 Safari/537.36.

However when I tried to get device_name, it returned nil along with these warnings:

/Users/victor/.rvm/gems/ruby-2.2.1/gems/device_detector-0.9.0/lib/device_detector/parser.rb:74: warning: character class has '-' without escape
/Users/victor/.rvm/gems/ruby-2.2.1/gems/device_detector-0.9.0/lib/device_detector/parser.rb:74: warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression
/Users/victor/.rvm/gems/ruby-2.2.1/gems/device_detector-0.9.0/lib/device_detector/parser.rb:74: warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression
/Users/victor/.rvm/gems/ruby-2.2.1/gems/device_detector-0.9.0/lib/device_detector/device.rb:53: warning: nested repeat operator '+' and '?' was replaced with '*' in regular expression
=> nil

Is this a bug for ruby 2.2.1?

Apple Podcasts (app) detected as "Mobile Safari"

irb(main):040:0> s = 'AppleCoreMedia/1.0.0.10B500 (iPod; U; CPU OS 6_1_6 like Mac OS X; en_gb)'
=> "AppleCoreMedia/1.0.0.10B500 (iPod; U; CPU OS 6_1_6 like Mac OS X; en_gb)"
irb(main):041:0> DeviceDetector.new(s).name
=> "Mobile Safari"

Android User Agent requires semicolons when others do not

curious why android_tablet_fragment? and android_mobile_fragment? require semicolons and other operating systems (Opera) do not? We don't use semicolons in our user agent at Kickstarter, and as far as I can tell there is no standardization here (please correct me if I'm wrong). Another example user agent from Facebook has a semicolon after Android but not after Mobile:

Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/43.0.2357.121 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/35.0.0.48.273;]

going to open a pr making the semicolon optional.

[Small Bug] DeviceDetector::full_version is returning platform version for Client Hints

Encountered a small bug while playing around with user agent client hints. (should be a one-line change)

The full_version method in DeviceDetector is calling client_hint.platform_version, which is the property used to get the os version.

It should be client_hint.full_version instead. This is the browser version. (the one that read from the Sec-CH-UA-Full-Version header)

Let me know if you need more information!

Introduce a separate cache for the regexp definitions not to expire them with results

While using the DeviceDetector gem I've noticed, that the same cache is being used to store the final detection results as well as to tackle the internal caching.

This approach causes a YAML reload of regexps when enough browsers are being recognized.

Here's an example of how to reproduce that:

require 'device_detector'

DeviceDetector.configure do |config|
  config.max_cache_keys = 10
end

module Bench
  def self.call
    t = Time.now.to_f
    r = yield
    p (Time.now.to_f-t)*1000
    r
  end
end

20.times do
  Bench.call { DeviceDetector.new(Time.now.to_f.to_s).full_version }
end

the result is:

16.92676544189453
0.14138221740722656
0.1392364501953125
0.1327991485595703
0.13113021850585938
28.29146385192871
0.7753372192382812
0.11897087097167969
0.11181831359863281
45.581817626953125
1.2042522430419922
1.0809898376464844
1.1005401611328125
17.076730728149414
0.12612342834472656
0.11444091796875
0.10657310485839844
27.06766128540039
0.13065338134765625
0.1087188720703125

So we see spikes in the time needed due to reloading of yaml definitions.

After applying the following patch:

module Patches
  module DeviceDetectorParser
    CACHE = ::DeviceDetector::MemoryCache.new({})

    private_constant :CACHE

    def regexes_for(file_paths)
      CACHE.get_or_set(filepaths) do
        super
      end
    end
  end
end

DeviceDetector::Parser.prepend(Patches::DeviceDetectorParser)

the results are always consistent as only the "public" results are being purged while keeping the regexp definitions intact in the cache.

require 'device_detector'

DeviceDetector.configure do |config|
  config.max_cache_keys = 10
end

module Patches
  module DeviceDetectorParser
    CACHE = ::DeviceDetector::MemoryCache.new({})

    private_constant :CACHE

    def regexes_for(file_paths)
      CACHE.get_or_set(filepaths) do
        super
      end
    end
  end
end

DeviceDetector::Parser.prepend(Patches::DeviceDetectorParser)

module Bench
  def self.call
    t = Time.now.to_f
    r = yield
    p (Time.now.to_f-t)*1000
    r
  end
end

20.times do
  Bench.call { DeviceDetector.new(Time.now.to_f.to_s).full_version }
end

Result:

19.721269607543945
1.1222362518310547
0.8854866027832031
0.1773834228515625
0.1361370086669922
0.1354217529296875
0.1327991485595703
0.13184547424316406
0.1277923583984375
0.13184547424316406
0.12993812561035156
0.1289844512939453
0.13017654418945312
0.13184547424316406
0.12826919555664062
0.13208389282226562
0.13065338134765625
0.12731552124023438
0.12969970703125
0.13637542724609375

if that approach is ok, I can make a PR.

Concurrency issue in MemoryCache

Hi!

We're running DeviceDetector in Sidekiq and under high load we sometimes are able to get NoMethodError: undefined method '[]' for nil:NilClass from:

"/webapps/api/vendor/bundle/ruby/2.6.0/gems/device_detector-1.0.1/lib/device_detector/os.rb" line 11 in short_name
"/webapps/api/vendor/bundle/ruby/2.6.0/gems/device_detector-1.0.1/lib/device_detector.rb" line 66 in device_type

That's basically a MemoryCache#get_or_set call which returns nil.

Here's the code for reference:

def get_or_set(key, value = nil)
string_key = String(key)
if key?(string_key)
get(string_key)
else
value = yield if block_given?
set(string_key, value)
end
end

My belief what happens is:

  1. The cache is full and it will be purged on the next write
  2. Thread 1 In line 33 we check if the given key K1 exists
  3. Thread 2 in the meantime calls cache.set('k2', 1) and purges the cache. K1 was an old key and got purged
  4. Thread 1 tries to get(K1) and returns, but there is no such key now so it returns nil

Here's a script that can replicate it:

require 'device_detector'

cache = DeviceDetector::MemoryCache.new(max_cache_keys: 3)

# fill the cache 100% capacity
cache.set(1, 1)
cache.set(2, 2)
cache.set(3, 3)

# now on, the oldest keys should be purged on each write

sampler = (1..4).to_a

threads = 20.times.map do |thread_id|
  Thread.new do
    1_000_000.times do |i|
      val = sampler.sample

      ret = cache.get_or_set(val, val)

      puts "[Thread #{thread_id}] BOOM" if ret.nil?
    end
  end
end

threads.each(&:join)

A simple solution would be to remove the check key?(string_key) and just get the value and return it if it's non-nil.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.